前言
在深入分析源码之前,我们再来拎一下FutureTask到底是干嘛的。人如其名,FutureTask包含了Future和Task两部分。
FutureTask实现了RunnableFuture接口,RunnableFuture接口又继承了Runnable和Future接口,所以FutureTask既有Runnable执行任务的功能,又有Futrue获取结果的功能。
状态、队列、cas是Java并发工具中的三板斧,像AQS、Condition、FutureTask等都是基于此实现的。
状态
在FutrueTask状态是用state属性来表示的,被valatile修饰,代表修改结果对其它线程立即可见且不允许重排序。
private volatile int state; // 状态
private static final int NEW = 0; // 新建状态
private static final int COMPLETING = 1; // 设置结果中
private static final int NORMAL = 2; // 正常结束
private static final int EXCEPTIONAL = 3; // 异常
private static final int CANCELLED = 4; // 取消
private static final int INTERRUPTING = 5; // 设置中断中
private static final int INTERRUPTED = 6; // 已中断
state是贯穿整个FutureTask最核心的属性,属性的值代表不同的执行状态,随着任务的执行,状态在不断变化,FutureTask共定义了七种状态:1个初始状态,2个中间状态,3个最终状态。
虽说状态有这么多,但是状态的转换路径却只有四种:
每种状态的含义上面代码已经注释了,在此不在说明。
队列
FutureTask队列是基于Treeber stack实现的单向列表,所有等待结果的线程最后都会加入到Treeber stack中。
对Treeber stack不太熟悉的,可以看这里。
static final class WaitNode {
volatile Thread thread; // 对应的线程
volatile WaitNode next; // 下一个节点
WaitNode() { thread = Thread.currentThread(); } // 设置当前执行的线程
}
在FutureTask中有一个waiters属性指向此栈的栈顶节点。
private volatile WaitNode waiters; // Treiber栈 指向栈的栈顶节点
队列结构:
源码分析
主要属性
/**
* The run state of this task, initially NEW. The run state
* transitions to a terminal state only in methods set,
* setException, and cancel. During completion, state may take on
* transient values of COMPLETING (while outcome is being set) or
* INTERRUPTING (only while interrupting the runner to satisfy a
* cancel(true)). Transitions from these intermediate to final
* states use cheaper ordered/lazy writes because values are unique
* and cannot be further modified.
*
* Possible state transitions:
* NEW -> COMPLETING -> NORMAL
* NEW -> COMPLETING -> EXCEPTIONAL
* NEW -> CANCELLED
* NEW -> INTERRUPTING -> INTERRUPTED
*/
private volatile int state; // 状态
private static final int NEW = 0; // 新建状态
private static final int COMPLETING = 1; // 设置结果中
private static final int NORMAL = 2; // 正常结束
private static final int EXCEPTIONAL = 3; // 异常
private static final int CANCELLED = 4; // 取消
private static final int INTERRUPTING = 5; // 设置中断中
private static final int INTERRUPTED = 6; // 已中断
private Callable<V> callable; // 任务
private Object outcome; // non-volatile, protected by state reads/writes // 保存结果,正常完成或者异常
private volatile Thread runner; // 执行任务的线程
private volatile WaitNode waiters; // Treiber栈 指向栈的栈顶节点
private static final sun.misc.Unsafe UNSAFE; // 魔法类
private static final long stateOffset; // 状态偏移量
private static final long runnerOffset; // 任务执行线程偏移量
private static final long waitersOffset; // 指向栈顶节点的偏移量
主要方法
FutureTask实现了RunnableFuture,RunnableFuture又继承了Runnable和Future,所以FutureTask也间接实现了Runnable。
run
public void run() {
if (state != NEW || // 如果state 不是初始状态或者更新当前执行线程失败,则直接返回,保证任务只能一个线程执行
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread())) // 原子更新执行任务线程
return;
try {
Callable<V> c = callable; // 任务
if (c != null && state == NEW) { // 任务不是null且执行状态是初始状态,再次说明一个任务有且只能有一个线程去执行
V result; // 保存执行结果
boolean ran; // 任务是否正常完成
try {
result = c.call(); // 执行任务的call方法
ran = true;
} catch (Throwable ex) { // 执行业务代码出现异常
result = null;
ran = false;
setException(ex); // 设置抛出的异常
}
if (ran)
/**
* 如果在任务执行过程中,有其它线程调用了cancle(false),业务代码也会正常执行完
* 只是在赋值执行结果的时候回赋值失败,因为state已经从“NEW”变成“CANCELLED”
*/
set(result); // 任务正常结束,设置返回结果
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
/**
* 在当前线程执行run方法的同时,有可能其他线程取消了任务的执行,
* 此时其他线程就可能对state状态进行改写,这也就是我们在设置终止状态的时候用putOrderedInt方法,
* 而没有用CAS操作的原因——我们无法确信在设置state前是处于COMPLETING中间态还是INTERRUPTING中间态。
*/
int s = state;
if (s >= INTERRUPTING) // 如果状态还是中间状态就等待变成最终状态
handlePossibleCancellationInterrupt(s); // 处理中断
}
}
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) { // 如果线程从“初始”状态原子更新为“完成中”
outcome = v; // 赋值执行结果
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state 直接设置成完成
finishCompletion(); //收尾工作,循环唤醒等待该任务结果的所有线程
}
}
protected void setException(Throwable t) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) { // 如果线程从“初始”状态更新为“完成中”
outcome = t; // 赋值异常结果
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
finishCompletion(); //收尾工作,循环唤醒等待该任务结果的所有线程
}
}
run方法内部相对还是比较简单的,简单的说下run的执行流程:
- 如果状态是初始状态且没有其它线程执行过
- 执行call方法
2.1 正常执行结束,调用set方法,把结果赋值给outcome属性,更新state 为"NORMAL", 调用finishCompletion方法唤醒等待的线程
2.2 执行业务代码出现异常,调用setException,把异常赋值给outcome属性,更新state 为"EXCEPTIONAL",调用finishCompletion方法唤醒等待的线程 - 收尾工作,等待状态变成最终状态
finishCompletion
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) { // 从栈的栈顶开始遍历
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) { // 清空Treiber栈
for (;;) { // 循环唤醒等待在该任务的所有线程
Thread t = q.thread;
if (t != null) {
q.thread = null;
LockSupport.unpark(t); // 唤醒等待的线程
}
WaitNode next = q.next;
if (next == null) // 如果已经到达栈的尾部,就退出循环
break;
q.next = null; // unlink to help gc
q = next;
}
break;
}
}
done();
callable = null; // to reduce footprint
}
此方法的工作就是唤醒等待结果的线程
get
public V get() throws InterruptedException, ExecutionException {
int s = state; // 状态
if (s <= COMPLETING) // 如果是初始状态或者设置结果中状态,就加入队列等待
s = awaitDone(false, 0L);
return report(s);
}
private V report(int s) throws ExecutionException {
Object x = outcome; // 结果
if (s == NORMAL) // 正常结束状态
return (V)x;
if (s >= CANCELLED) // 如果取消或者中断,在这里不会有中间状态发生了,因为不管是正常返回结果,还是执行call出现异常或者
// 其它线程取消了该任务,都会等待更新到最终状态才会唤醒等待结果的线程
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}
该方法其实很简单,当任务还没有执行完毕或者正在设置执行结果时,我们就使用awaitDone方法等待任务进入终止态,注意,awaitDone的返回值是任务的状态,而不是任务的结果。任务进入终止态之后,我们就根据任务的执行结果来返回计算结果或者抛出异常。
我们先来看看等待任务完成的awaitDone方法,该方法是获取任务结果最核心的方法,它完成了获取结果,挂起线程,响应中断等诸多操作:
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
final long deadline = timed ? System.nanoTime() + nanos : 0L; // 如果设置了超时时间,计算下多久之后超时
WaitNode q = null;
boolean queued = false;
for (;;) {
if (Thread.interrupted()) { // 如果中断,则删除节点
removeWaiter(q);
throw new InterruptedException();
}
int s = state;
if (s > COMPLETING) { // 任务已经完成
if (q != null) // 如果已经创建过节点
q.thread = null;
return s; // 返回状态
}
else if (s == COMPLETING) // cannot time out yet 如果状态是设置结果中,则放弃cpu
Thread.yield();
else if (q == null)
q = new WaitNode(); // 创建等待节点
else if (!queued)
/*
这里是使用的Treeber栈,把新入节点原子更新为栈顶节点
*/
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
else if (timed) { // 设置了超时
nanos = deadline - System.nanoTime();
if (nanos <= 0L) { // 超时,删除节点
removeWaiter(q);
return state;
}
LockSupport.parkNanos(this, nanos); // 超时挂起
}
else
LockSupport.park(this); // 挂起线程
}
}
cancel
/*
取消任务:
有几种情况不能取消
1: 任务已经完成
2: 任务已经取消
3: 其它情况导致的不能取消
*/
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW && // 如果任务已经完成,则不能取消
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED))) // 如果任务已经完成或者任务已经取消过,则不能再次取消
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) { // 中断
try {
Thread t = runner; // 执行任务的线程
if (t != null)
/**
* 中断执行任务的线程,此中断只是发送一个中断信号,具体能不能中断,完全取决于任务代码支不支持线程中断操作
*/
t.interrupt();
} finally { // final state
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED); // 直接设置成已经中断
}
}
} finally {
finishCompletion(); // 收尾工作,唤醒等待队列中的线程
}
return true; // 返回true,不代表真正的中断了
}
总结
FutureTask实现了Runnable和Future接口,它表示了一个带有任务状态和任务结果的任务,它的各种操作都是围绕着任务的状态展开的,值得注意的是,在所有的7个任务状态中,只要不是NEW状态,就表示任务已经执行完毕或者不再执行了,并没有表示“任务正在执行中”的状态。
除了代表了任务的Callable对象、代表任务执行结果的outcome属性,FutureTask还包含了一个代表所有等待任务结束的线程的Treiber栈,这一点其实和各种锁的等待队列特别像,即如果拿不到锁,则当前线程就会被扔进等待队列中;这里则是如果任务还没有执行结束,则所有等待任务执行完毕的线程就会被扔进Treiber栈中,直到任务执行完毕了,才会被唤醒。
FutureTask虽然为我们提供了获取任务执行结果的途径,遗憾的是,在获取任务结果时,如果任务还没有执行完成,则当前线程会自旋或者挂起等待。