Java使用Future、Callable和FutureTask
在使用多线程的时候,可以继承Thread类或者实现Runnable接口,这样就可以启动一个线程并运行了。但是这种模式有个问题,就是无法获取到线程调用的结果。要获取结果的话必须使用共享变量或者线程通信的方式来达到效果,这样使用起来比较麻烦。于是JDK就从1.5之后引入了Future和Callable,来在线程执行完成之后,获得线程执行的结果。
这里,我们先研究分析一下Future、Callable以及衍生出的FutureTask。
Future示例
先看一个使用Future的例子
1 | public class FutureTest { |
首先新建了一个只有一个线程的线程池,而后向线程池提交了一个任务,任务的返回值是一个Future<String>对象。
任务执行的内容很简单,就是等待3秒,返回字符串“Hello World”。
最后打印返回的结果和耗时,然后关闭线程池。下面是运行结果:
从图中可以看到,到出结果之前一共耗费了3秒左右,那是因为,在Future对应的线程没有完成之前,调用Future.get的话,会被阻塞住,直到线程运行结束,有结果返回位置。
Future接口
Future是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。
Future类位于java.util.concurrent包下
1 | public interface Future<V> { |
Callable示例
1 | class Sum implements Callable<Integer> { |
首先声明一个类,它需要继承Callable接口,并实现它的call方法。从代码中可以看到,call方法是有返回值的。
接着,我们在main函数中,声明了一个只有一个线程的线程池,提交一个新的Callable任务。用Future对象去获得它的运行结果。
最后打印结果,耗时和关闭线程池。
Callable接口
1 |
|
Callable接口就一个方法call,返回一个计算值。
FutureTask示例
1 | class FutureTaskSum implements Callable<Integer> { |
首先,将Callable中的例子Sum换了个名字
接着再main类中定义一个FutureTask<Integer>变量,并重写它的done方法
然后,新建一个单线程的线程池,提交这个FutureTask变量执行。
FutureTask类
FutureTask实现了RunnableFuture接口,而RunnableFutrue就是Runnable和Future的组合接口。
1 | /** |
所以FutureTask既能当做一个Runnable直接被Thread执行,也能作为Future用来得到Callable的计算结果。