FutureTask是一个可取消的异步计算框架。其中内部用的是state来记录任务的执行状态。java
如上所示FutrueTask内部封装了以上的Object。全部经过调用Futuretask执行的任务都会在齐内部包装成一个callable来执行。node
以上贴出的两个FutureTask的构造函数,要么直接构造一个实现了callable接口的对象,要么传入一个实现Runnable接口的对象,在其内部将Runnable转换为callable。多线程
接下来看看FutureTask的核心方法框架
可经过将FutureTask放入一个线程,或者将其放入线程池中实现调用。其中set()和setException()会唤醒存在waiters中的node,告诉他们计算已经完成,或者计算中抛出了异常。
在set()、setException()和cancel()方法的末尾都会调用finishCompletion()方法来释放存在waiters中的线程,在该方法中还有一个done()方法,用来让子类实现,作一些异步任务完成以后的事情。
看看cancel()方法异步
须要注意的是任务只有在state == NEW的时候才能被取消。函数
FutureTask可经过get()调用获得计算的结果,若是计算还没完成,该方法会阻塞,也可响应中断。产生阻塞的时候会将线程wrap成node加入到waiters中。下面看看get中调用的awaitDone(boolean timed, long nanos)方法this
awaitDone代码中采起死循环的方式:
检查是否响应中断,如果,则移除该node,抛出中断异常。spa
if (Thread.interrupted()) { removeWaiter(q); throw new InterruptedException(); }
若此时已经结束,返回此时的状态值。线程
int s = state; if (s > COMPLETING) { if (q != null) q.thread = null; return s; }
若判断为如下状况则暂时让出cpu时间,稍后执行,由于COMPLETING是一个瞬时的状态,说明这个时候计算结果已经立刻要被set了,或者也多是抛出了异常。code
else if (s == COMPLETING) // cannot time out yet Thread.yield();
若判断为如下状况则新建一个node,该node包装了当前的线程。
else if (q == null) q = new WaitNode()
若判断为如下状况则将node加入到waiters中
else if (!queued) queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q);
接下来最后的两个判断都是park这个线程,只是有时间的区分。
利用FutureTask和ExecutorService,能够用多线程的方式提交计算任务,主线程继续执行其余任务,当主线程须要子线程的计算结果时,在异步获取子线程的执行结果。