2、为什么我们需要Callable接口
可以将任务分开多线程去做,并通过返回值的方式汇总到主线程,输出结果。
3、注意点
3.1、futureTask.get():
如无必须,要放在最后,因为get()方法要求获得Callable线程的返回值,如果没有计算完成会导致堵塞,直到计算完成。
也就是说,调用get方法就需要得到结果,一旦有多个未知效率的FutureTask,如何安排其get方法的调用顺序将成为一个问题。
package com.company;
import java.util.concurrent.*;
class MyThread2 implements Callable<Integer>
{
@Override
public Integer call() throws Exception {
System.out.println("task3 start");
//一个非常复杂耗时的运算过程
try{TimeUnit.SECONDS.sleep(5);}catch (Exception e){e.printStackTrace();}
System.out.println("经过了一个非常复杂耗时的运算过程之后");
return 44;
}
}
public class CallableDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//task 1
int i = 10+1;
System.out.println("task 1:i = " + i);
//task 2
int j = 12-1;
System.out.println("task 2:j = " + j);
//task 3
//FutureTask实现了Runnable接口,同时提供了一个入参为Callable的构造方法
FutureTask<Integer> futureTask = new FutureTask<>(new MyThread2());
Thread t1 = new Thread(futureTask,"AAAA");
t1.start();
try{TimeUnit.SECONDS.sleep(1);}catch (Exception e){e.printStackTrace();}
//task 4
int x = 1;
System.out.println("task 4:x = " + x);
System.out.println("最终四个task运算的结果是:" + (i+j+futureTask.get())*x);
}
}
while(!futureTask.isDone()){
}
int a = futureTask.get();
FutureTask
可取消的异步计算。 该类提供了一个Future
的基本实现,具有启动和取消计算的方法,查询计算是否完整,并检索计算结果。 结果只能在计算完成后才能检索; 如果计算尚未完成,则get
方法将阻止。 一旦计算完成,则无法重新启动或取消计算(除非使用runAndReset()
调用[计算]。FutureTask
可用于包装Callable
或Runnable
对象。 因为FutureTask
实现Runnable
,一个FutureTask
可以提交到一个Executor
执行。
除了作为独立类之外,此类还提供了protected
功能,在创建自定义任务类时可能很有用。
3.2、一旦计算完成,则无法重新启动或取消计算(除非使用runAndReset()
调用[计算]。
同一个计算过程只能有一个线程进行运算,其他线程不能再启动这个计算。