一、简介
1. 类继承关系
2. 状态
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 volatile int state;
/** The underlying callable; nulled out after running */
private Callable<V> callable;
/** The result to return or exception to throw from get() */
private Object outcome; // non-volatile, protected by state reads/writes
/** The thread running the callable; CASed during run() */
private volatile Thread runner;
/** Treiber stack of waiting threads */
private volatile WaitNode waiters;
state表示FutureTask的状态。
FutureTask使用了delegate模式,callable就是其委派对象,具体的业务执行由callable对象进行。
由于FutureTask是Runnable的实现类,为了实现对callable任务的封装,可以获取callable的执行结果,FutureTask将callable的执行结果或者执行过程中抛出的异常保存在outcome中。
runner执行任务的线程
WaitNode 的定义如下,可以看到是一个链表式的结果,waiters表示等待中的线程集。
static final class WaitNode {
volatile Thread thread;
volatile WaitNode next;
WaitNode() { thread = Thread.currentThread(); }
}
三、构造方法
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
分别根据runnable或者callable作为FutureTask的callable对象,并将状态初始化为NEW。
四、状态判断
public boolean isCancelled() {
return state >= CANCELLED;
}
public boolean isDone() {
return state != NEW;
}
isCancelled表示FutureTask是否被取消,包括CANCELLED, INTERRUPTING, INTERRUPTED。
isDone表示FutureTask是否已经进行过操作,包括取消操作和执行任务的操作。
五、核心方法
1. FutureTask#run()
FutureTask既然是Runnable的实现类,其run方法自然就是我们关注的重点。
public void run() {
//检查并设置执行的线程
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
//callable 和 state 检查
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
//状态重置前runner必须不能为null,防止并发
// 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
int s = state;
//中断处理
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
2. FutureTask#setExecption(Throwable)
protected void setException(Throwable t) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = t;
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
finishCompletion();
}
}
异常赋值给outcome,设置状态,并调用finishCompletion进行收尾工作。
可以看到COMPLETING只是一个任务执行过程中的一个短暂的中间状态,用于防止并发。
3. FutureTask#set(V)
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
setExecption是FutureTask的异常处理,而该方法则是正常完成的处理逻辑。
执行结果赋值给outcome,设置状态,并调用finishCompletion进行收尾工作。
4. FutureTask#finishCompletion
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
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
}
(1)遍历waiters,将其中的线程移除并发送信号唤醒线程进行执行。
双重循环,外层循环用于CAS修改waiters为null值的失败重试,内层循环用于遍历waiters
(2)调用done方法。
done方法时执行完成时的钩子函数,FutureTask本身并没有做任何动作,留给子类进行扩展。
protected void done() { }
(3)callable置为null。
5. FutureTask#handlePossibleCancellationInterrupt(int)
/**
* Ensures that any interrupt from a possible cancel(true) is only
* delivered to a task while in run or runAndReset.
*/
private void handlePossibleCancellationInterrupt(int s) {
// It is possible for our interrupter to stall before getting a
// chance to interrupt us. Let's spin-wait patiently.
if (s == INTERRUPTING)
while (state == INTERRUPTING)
Thread.yield(); // wait out pending interrupt
// assert state == INTERRUPTED;
// We want to clear any interrupt we may have received from
// cancel(true). However, it is permissible to use interrupts
// as an independent mechanism for a task to communicate with
// its caller, and there is no way to clear only the
// cancellation interrupt.
//
// Thread.interrupted();
}
中断来自于在run和runAndReset方法执行过程中的cancel(true)操作,对于中断的处理就是通过线程让步的方式等待取消逻辑执行完成。
6. FutureTask#runAndReset()
/**
* Executes the computation without setting its result, and then
* resets this future to initial state, failing to do so if the
* computation encounters an exception or is cancelled. This is
* designed for use with tasks that intrinsically execute more
* than once.
*
* @return {@code true} if successfully run and reset
*/
protected boolean runAndReset() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return false;
boolean ran = false;
int s = state;
try {
Callable<V> c = callable;
if (c != null && s == NEW) {
try {
c.call(); // don't set result
ran = true;
} catch (Throwable ex) {
setException(ex);
}
}
} 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
s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
return ran && s == NEW;
}
runAndReset方法也用于执行任务,与run方法不同的是,该方法不修改状态,也不会处理执行结果,只返回是否执行成功,这是为了可以反复执行任务,主要的使用场景就是ScheduledFutureTask类。
7. FutureTask#get
FutureTask共有两个get方法用于获取任务的执行结果,分别是不限时的FutureTask#get()和限时的FutureTask#get(long, TimeUnit),两者的逻辑类似,以FutureTask#get(long, TimeUnit)为例解析
public V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
if (unit == null)
throw new NullPointerException();
int s = state;
if (s <= COMPLETING &&
(s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
throw new TimeoutException();
return report(s);
}
(1)null值检查
(2)如果当前任务未完成,阻塞等待一段时间
(3)如果等待一段时间后还未完成,抛出超时异常TimeoutException
(4)通过report方法返回执行结果。
8. FutureTask#report(int)
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL)
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}
根据状态值返回不同的结果。
任务正常完成,返回执行结果
任务被取消,抛出异常CancellationException
任务异常结束,将抛出的异常封装成ExecutionException抛出
9. FutureTask#awaitDone(boolean, long)
同样有两个方法,用于get方法中等待任务完成或被取消,返回方法执行结束时的状态
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)
//封装成WaitNode,适用于刚进入循环的场景
q = new WaitNode();
else if (!queued)
//加入链表waiters
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);
}
}
//链表移除指定节点
private void removeWaiter(WaitNode node) {
if (node != null) {
node.thread = null;
retry:
for (;;) { // restart on removeWaiter race
for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
s = q.next;
if (q.thread != null)
pred = q;
else if (pred != null) {
pred.next = s;
if (pred.thread == null) // check for race
continue retry;
}
else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,
q, s))
continue retry;
}
break;
}
}
}
在循环中进行检查,被中断或执行加上或超时后返回状态,否则封装成WaitNode并加入到waiters中,通过LockSupport.park进行阻塞。
可以看到,在finishCompletion方法中会通过LockSupport.unpark发送信号,取消线程的阻塞。
10. FutureTask#cancel(boolean)
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;
}
只有在线程的状态为NEW(没有进行任何操作)时,才可以进行取消。
对于参数为false的场景,不进行线程中断,直接将状态修改为CANCELLED。
对于参数为true的场景,需要进行线程中断,将状态改为过渡值INTERRUPTING防止并发,然后发送中断信号后再修改状态值为INTERRUPTED,最后finishCompletion唤醒所有阻塞线程。
线程被中断不代表线程被取消,只是调用t.interrupt(),此时,如果t因为sleep(),wait()等方法进入阻塞状态,那么阻塞的地方会抛出InterruptedException;如果线程正常运行,需要结合Thread的interrupted()方法进行判断,才能结束,否则,cancel(true)不能结束正在执行的任务。