在Java5以后,通过Executor来启动线程比用Thread的start()更好。在新特征中,可以很容易控制线程的启动、执行和关闭过程,还能使用线程池的特性。上一篇我们介绍了线程池的基本用法和特性。我们用的最多的是ExecutorService的execute方法,它帮我们把线程任务交给线程池,剩下就不管了,也不关心返回值。那么如果我们向把任务交给线程池处理,同时又期望得到结果,这时候怎么做呢?
0.异步返回值的场景
我们先不用线程池,来实现一个功能。加入周末了,几个小伙伴要一块做饭,假设做饭需要3个步骤,分别是:
1.打扫厨房卫生,准备厨具
2.买菜
3.炒菜
现在我们怎么分工呢,现实中一般是这样的,一部分小伙伴去买菜,一部分小伙伴打扫准备厨具,等这两样都做完之后才炒菜。也就是说第1步和第2步是同时进行的。
我们使用Java代码来实现下:
public class Cook{
public static void futureCook() throws ExecutionException, InterruptedException {
Callable<Food> first = new Callable<Food>() {
@Override
public Food call() throws Exception {
//do something
return new Food();
}
};
FutureTask<Food> task1 = new FutureTask<Food>(first);
new Thread(task1).start();//先去做第一步
Object task2 = null;
//.... 第二步做了一些事
// 第三步 需要用到第一步和第二部的结果
if (!task1.isDone()) { // 第一步是否完成
System.out.println("task1 is done");
}
Food foods = task1.get();//获取第一步的结果
cook(foods, task2);
}
private static void cook(Food foods, Object task2) {
}
static class Food{
Object food;
}
}
我们先用一个线程去买菜,执行第一步,同时执行第二步,第二步完成之后,我们试图获取第一步的结果,如果第一步没有执行完,那么就阻塞在这里等待,直到完成。前两步完成之后,我们就可以愉快的做饭了。
下面我们分析下使用到的技术
1.Callable
Callable是一个接口,它只有一个方法call,调用call可以异步执行,并返回结果。
public interface Callable<V> {
/**
* Computes a result, o