FutureTask类的get方法如何实现线程同步等待
在JDK中实现线程同步等待闭环(FutureTask/Future),为什么使用了FutureTask中的get方法就可以实现线程的同步等待?这就将重点讲述下FutureTask这个类了,实际上Future接口和实现Future接口的FutureTask类,表示异步计算的结果。其UML类继承图,如下:
从上图看FutureTask除了实现Future接口外,还实现了Runnable接口。因此,FutureTask可以交给Executor执行,也可以由调用线程直接执行(FutureTask.run())。根据FutureTask.run()方法被执行的时机,FutureTask可以处于下面3种状态(线程状态转换参考线程基本方法及其对线程状态的影响 - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)):
1)未启动。FutureTask.run()方法还没有被执行之前,FutureTask处于未启动状态。当创建一个FutureTask,且没有执行FutureTask.run()方法之前,这个FutureTask处于未启动状态。
2)已启动。FutureTask.run()方法被执行的过程中,FutureTask处于已启动状态。
3)已完成。FutureTask.run()方法执行完后正常结束,或被取消(FutureTask.cancel(…)),或执行FutureTask.run()方法时抛出异常而异常结束,FutureTask处于已完成状。
当FutureTask处于未启动或已启动状态时,执行FutureTask.get()方法将导致调用线程阻塞;当FutureTask处于已完成状态时,执行FutureTask.get()方法将导致调用线程立即返回结果或抛出异常——非常类似于闭锁的语义。
看看get()方法的实现:
通过源码可以看到:get()方法使用AQS类型的同步状态来持有任务的状态——运行、完成或者取消(state变量),同时利用state变量也维护了一些额外的状态变量来持有计算的结果或者抛出异常。与利用AQS类实现同步器的类是不是似曾相识(#^.^#),所以FutureTask虽然代表异步执行的结果,但是可以通过get方法阻塞当前正在运行的线程实现同步等待异步结果。
其还维护一个WaitNode q 指向正在运行计算任务的线程(当前正处于运行状态),这样任务被取消就可以终止该线程:
get()方法的执行示意图如下图上半部分: