讲FutureTask之前,先讲讲Runnable,Callable,Future,FutureTask之间都是啥关系?
在接触Callable之前,我们都说,开线程执行一个方法是获取不到返回值的。为什么这么说呢?
首先是Runnable接口,我们一般实现该接口后都会重写run()方法,这里可以看到run()方法是没有返回值的。也就是说,如果你在run()方法里面,做了一次数据库查询操作,获取到的结果是无法通过方法返回的。只能通过别的方式来获取,比如你可以赋值给一个静态变量或者全局变量,会特别麻烦。
public abstract void run();
而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;
}
常见的用法:
private ExecutorService exe=Executors.newFixedThreadPool(2);
private void CallableTest(){
Callable<Integer> c=new Callable<Integer>() {
@Override
public Integer call() throws Exception {
//假设这里花费了2S做了复杂的计算操作
Thread.sleep(2*1000);
return 222;
}
};
Future<Integer> f=exe.submit(c);
//这中间可以做一些别的操作
try {
Integer result =f.get();//在需要的时候再来获取执行的结果
System.out.println(result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
通常是实现Callable接口的call()方法,然后在里面写你的逻辑。创建好之后,把它提交到线程池中,它就会执行。然后在你需要获取结果的时候,调用future.get()方法获取执行的结果。因为Callable是可以获取返回值的,所以我们可以把一些耗时的任务放在前面执行,然后在后面需要的结果的时候再来获取。
那Future又是啥呢?可以看到,我们前面是通过Future.get()来获取Callable返回的结果,还可以通过Future.isDone()来判断任务是否已经执行完了,以及取消这个任务,限时获取任务的结果等。而如果任务没有执行完,future.get()会阻塞调用的线程直到任务执行完后返回结果。
FutureTask则是实现Future这么多功能的核心。
FutureTask实现了RunnableFuture接口,RunnableFuture接口则是继承了Runnable,Future接口类。FutureTask类用于包装Callable和Runnable,然后提交给线程池执行。