注:本文针对FutureTask状态之间含义及转换参考博客:http://www.importnew.com/25286.html;感谢此博主提供非常详细的介绍,大家可以看看。
上一遍我们将Callable接口结合FutureTask的使用以及一些源码进行简单的解释;这一篇我们将继续深入FutureTask这个类。
我们先从FutureTask这个类的源码跟
第一个构造方法
FutureTask构造方法之一,这个构造函数会将传入过来的callable对象进行保存,赋值给this.callable,也就是我们下图定义的private Callable(v) callable;然后在将FutureTask内部执行的任务状态保存在state中,初始化是NEW。
可以看到,state被定义为volatile类型(线程可见性,一个线程的修改状态对另外一个线程是可见的);提供了7种状态进行表述任务状态
NEW:任务的初始状态,表示一个新的任务或者还没被执行的任务。(NEW)
COMPLETING: 任务已经执行完成或者任务在执行过程中发什么了异常,但是任务的执行结果和异常还没有保存到outcome;也就是上图private Object outcome,这是一个中间态;(NEW——COMPLETING)
NORMAL:任务已经成功执行完成,并且结果已经保存在了outcome,这是一个最终态;(COMPLETING——NORMAL)
EXCEPTIONAL:任务在执行中发生异常,并且异常状态信息已经保存到outcome,这是一个终态;(COMPLETING——EXCEPTIONAL);
CANCELLED:任务还没有开始执行或者正在执行的过程中,调用了cancel(true)方法取消任务且不中断任务执行线程;任务执行状态从NEW——CANCELLED
INTERRUPTING:任务还没有开始执行或者正在执行的过程中,调用了cancel(true)方法取消任务,并且要中断线程任务,但是任务还没有被中断之前,状态从NEW——INTERRUPTING,这是一个中间状态;
INTERRUPTED:调用interrupt()中断任务执行线程之后状态会从INTERRUPTING——INTERRUPTED,这是一个最终态;
上图注释部分描述了状态之间的转换关系
第二个构造方法
上一遍我们说到此构造方法使用的适配器模式将Runnable适配成Callable;接下来我们深入看看它的源码
跟进RunnableAdapter
我们看到这个适配器实现的是Callable接口,而call方法中task.run();调用的就是Runnable的run()方法,并且将传入的result作为任务的结果返回。看下面这个demo
执行结果:
不管我们利用什么方式执行任务,都是执行FutureTask这个类中的run()方法;结合上面讲述的任务执行状态,我们接着往下看run()方法的源码
finally中对任务进行状态回溯,如果任务状态是INTERRUPTING(任务执行了取消,并且还没进行中断任务之前);则执行中断处理!
调用yield()方法暂停当前任务,进行线程让步;
整个线程执行完成后,最终结果是存储在outcome中,这时候我们利用FutureTask中的get方法进行结果或者异常信息获取;我们看看get()源码,发现get()方法是一个重载方法,有两个,第一个是直接获取结果(判断状态s<=COMPLETING是否成立),第二个是指定超时时间获取结果,如果超时了任务还未完成,则抛出状态,最后返回report()方法;
总结:FutureTask类中实现了Future接口中很多方法,包括cancel()任务取消;isCancelled()判断是否取消成功;isDone()判断任务是否执行等其他的方法,这些没有在此文章中体现;只是将了一个正常情况下的多线程任务执行结果及状态结果的接收;写的不是很好,请大家见谅。