Callable,Future和FutureTask详解
1.Callable和Runnable
看Callable接口:
public interface Callable<V> { /** * Computes a result, or throws an exception if unable to do so. * * @return computed result * @throws Exception if unable to compute a result */ V call() throws Exception; }
看Runnable接口:
public interface Runnable { /** * When an object implementing interface <code>Runnable</code> is used * to create a thread, starting the thread causes the object's * <code>run</code> method to be called in that separately executing * thread. * <p> * The general contract of the method <code>run</code> is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run(); }
Callable和Runnable都代表着任务,不同之处在于Callable有返回值,并且能抛出异常,Runnable任务执行结束之后没有返回值。Callable一般和Future一起使用,可以获取任务返回结果。
2.Future接口
Future就是对具体的Callable和Runnable任务进行操作,如:取消任务,查询任务是否完成,获取任务完成之后的返回结果(如果有返回值)。看代码:
public interface Future<V> { // 用于取消任务 boolean cancel(boolean mayInterruptIfRunning); // 任务是否被取消成功,如果取消成功,返回true boolean isCancelled(); // 任务是否已经完成,如果完成,返回true boolean isDone(); // 获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回 V get() throws InterruptedException, ExecutionException; // 获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。 V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
由接口可知,Future提供了四种功能:
- 取消任务
- 判断任务是否取消成功
- 判断任务是否完成
- 获取任务执行结果
通过一个Demo来理解Future的用法:
public class FutureTest { public static class Task implements Callable<String>{ @Override public String call() throws Exception { System.out.println("开始执行任务。。。"); return "callable"; } } public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService es = Executors.newCachedThreadPool(); List<Future<String>> results = new ArrayList<Future<String>>(); for(int i = 0;i<100;i++){ results.add(es.submit(new Task())); } for(Future<String> res : results){ System.out.println(res.get()); } } }
3.FutureTask
public class FutureTask<V> implements RunnableFuture<V>
public interface RunnableFuture<V> extends Runnable, Future<V> { void run(); }
从代码可知:FutureTask既可以作为Runnable被线程执行,又具有Future的功能。
FutureTask的两种使用方式:
使用方式一:FutureTask+Thread
public class FutureTest { public static class Task implements Callable<String>{ @Override public String call() throws Exception { System.out.println("开始执行任务。。。"); return "callable"; } } public static void main(String[] args) throws InterruptedException, ExecutionException { //创建FutureTask对象,并传入一个实现了Callable接口的对象作为构造参数 FutureTask<String> futureTask = new FutureTask<String>(new Task()); //创建Thread并启动 Thread thread = new Thread(futureTask); thread.start(); } }
使用方式二:FutureTask+ExecutorService
public class FutureTest { public static class Task implements Callable<String>{ @Override public String call() throws Exception { System.out.println("开始执行任务。。。"); return "callable"; } } public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService es = Executors.newCachedThreadPool(); FutureTask<String> futureTask = new FutureTask<String>(new Task()); es.submit(futureTask); } }