Java 5在concurrency包中引入了java.util.concurrent.Callable 接口,它和Runnable接口很相似,但它可以返回一个对象或者抛出一个异常。
Callable接口使用泛型去定义它的返回类型。Executors类提供了一些有用的方法在线程池中执行Callable内的任务。由于Callable任务是并行的(并行就是整体看上去是并行的,其实在某个时间点只有一个线程在执行),我们必须等待它返回的结果。
java.util.concurrent.Future对象为我们解决了这个问题。在线程池提交Callable任务后返回了一个Future对象,使用它可以知道Callable任务的状态和得到Callable返回的执行结果。Future提供了get()方法让我们可以等待Callable结束并获取它的执行结果。
Callable接口的源码如下:
public interface Callable<V> { V call() throws Exception; // 计算结果 }
Future接口的源码如下:
public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning);// 试图取消对此任务的执行 boolean isCancelled(); // 如果在任务正常完成前将其取消,则返回 true boolean isDone(); // 如果任务已完成,则返回 true V get() throws InterruptedException, ExecutionException; // 如有必要,等待计算完成,然后获取其结果 // 如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)。 V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }Future用于表示异步计算的结果。它的实现类是FutureTask。
如果不想分支线程阻塞主线程,又想取得分支线程的执行结果,就用FutureTask
FutureTask实现了RunnableFuture接口,这个接口的定义如下:
public interface RunnableFuture<V> extends Runnable, Future<V> { void run(); }
可以看到这个接口实现了Runnable和Future接口,接口中的具体实现由FutureTask来实现。这个类的构造方法如下 :
public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; // state记录FutureTask的状态 this.state = NEW; // ensure visibility of callable }
public class MyCallable implements Callable<String> { private long waitTime; public MyCallable(int timeInMillis){ this.waitTime=timeInMillis; } @Override public String call() throws Exception { Thread.sleep(waitTime); //return the thread name executing this callable task return Thread.currentThread().getName(); } }
public class FutureTaskExample { public static void main(String[] args) { MyCallable callable1 = new MyCallable(1000); MyCallable callable2 = new MyCallable(2000); /* Future有两个构造器,一个以Callable为参数,另外一个以Runnable为参数。这些类之间的关联表明了 对于任务建模的办法非常灵活,允许你基于FutureTask的Runnable特性,把任务写成Runnable,然后封装 进一个由执行者调度并在必要时可以取消的FutureTask */ FutureTask<String> futureTask1 = new FutureTask<String>(callable1); FutureTask<String> futureTask2 = new FutureTask<String>(callable2); ExecutorService executor = Executors.newFixedThreadPool(2); executor.execute(futureTask1); executor.execute(futureTask2); while (true) { try { if(futureTask1.isDone() && futureTask2.isDone()){ System.out.println("Done"); //shut down executor service executor.shutdown(); return; } if(!futureTask1.isDone()){ //wait indefinitely for future task to complete System.out.println("FutureTask1 output="+futureTask1.get()); } System.out.println("Waiting for FutureTask2 to complete"); String s = futureTask2.get(200L, TimeUnit.MILLISECONDS); if(s !=null){ System.out.println("FutureTask2 output="+s); } } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); }catch(TimeoutException e){ //do nothing } } } }
When we run above program, you will notice that it doesn’t print anything for sometime because get()
method
of FutureTask waits for the task to get completed and then returns the output object. There is an overloaded method also to wait for only specified amount of time and we are using it for futureTask2. Also notice the use of isDone()
method
to make sure program gets terminated once all the tasks are executed.
Output of above program will be:
1
2
3
4
5
6
7
8
|
FutureTask1
output=pool-1-thread-1 Waiting for FutureTask2
to complete Waiting for FutureTask2
to complete Waiting for FutureTask2
to complete Waiting for FutureTask2
to complete Waiting for FutureTask2
to complete FutureTask2
output=pool-1-thread-2 Done |
As such there is no benefit of FutureTask but it comes handy when we want to override some of Future interface methods and don’t want to implement every method of Future interface.
Java 7之多线程线程池 - Callable和Future
原文:http://blog.csdn.net/mazhimazh/article/details/19291965