FutureTask类是并发编程的一个代表异步计算任务类,提供异步计算任务的封装以及异步计算结果的返回。本身实现Runnable接口,可以直接提交给线程池执行。
不过更多应该是配合Callable使用,因为要用到Callable.call()返回的结果封装在自己的outcome变量。
那为什么有了Callable还要用这个类?因为它提供了获取异步计算结果的机制,如果任务没执行完会阻塞获取线程等待任务结束。省去了工程师自己管理的流程。
本文基于JDK 8源码分析。FutureTask已经不依赖AQS的同步状态和同步队列了,直接使用unsafe实现get() run() cancle()等一套
首先认识下7种状态。最终状态有:正常结束、异常结束、已取消、已中断
state是维护的核心,外界线程想了解任务的状态就要靠它来完成。
JUC下很多无锁并发编程都是基于CAS提供的原子性保证并发安全。Redis分布式锁不正就是利用CAS思想做的。
public void run() {
// 一开始state=NEW,线程需要把自己写进runner变量。相当于拿锁
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
// 只有第一个进来的线程会遇到state=NEW,去执行Callable
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
// 1.2 异常结束,state改为异常
setException(ex);
}
// 1.1 正常运行完毕,设置outcome结果,并唤醒此FutureTask上挂起的线程,拿结果
if (ran)
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
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
protected void set(V v) {
// 把state从NEW改为COMPLETING,过渡状态
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
// 写结果
outcome = v;
// 从COMPLETING改为NORMAL最终状态,代表任务正常结束
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
// 1.1.1 善后工作,唤醒线程
finishCompletion();
}
}
FutureTask自己建立了一套等待队列机制,简单的Waiter单向链表,所有get()挂起线程都在这里等待。
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
// 把waiter链表头结点改为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.2 异常结束的流程跟正常结束流程基本一致,不同在于将异常对象写进outcome作为结果返回给外界。将state改为exceptional状态。同样的需要唤醒等待队列的线程。
FutureTask.get()原理更简单,直接通过state判断,到达最终状态直接返回outcome,否则按阻塞挂起/超时挂起进入等待队列,
public V get() throws InterruptedException, ExecutionException {
int s = state;
// state还处于NEW、COMPLETING,要等待
if (s <= COMPLETING)
// 2.1
s = awaitDone(false, 0L);
// 2.2 正常结束就返回outcome,异常或被取消就抛出异常。
return report(s);
}
超时等待是用指定时间挂起,等待指定时间唤醒后如果state还是未完成,会抛出TimeoutException
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
Thread.yield();
else if (q == null)
q = new WaitNode();
else if (!queued)
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 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);
}
cancel()有两种,cancel(true)是中断操作,cancel(false)是取消操作。
区别在于中断是会打断正在执行任务的线程,取消只是将state改为cancelled,不会打断线程。
然后两者都会将等待线程唤醒,线程被唤醒后都会抛出CancelledException
这里需要注意:cancel(false)只是将state改写了,从源码来看,工作线程执行完run()后因为state被改写,不会将结果写outcome。
cancel(true)也只是多了个设置runner线程中断标志位的操作,runner是否真的中断,要看代码怎么写,是否在执行过程中检查标志位,
Thread.interrupt()除此外只会对处于阻塞操作的线程造成直接影响,例如线程阻塞在wait() sleep() join() 等函数中/中断标志被开启了,再进入wait() join() sleep()也会抛出InterruptedException,线程的interrupt标志位会被清除复原,并且立即抛出InterruptedException。
public boolean cancel(boolean mayInterruptIfRunning) {
// 第一步,state=NEW并且将state成功改写为 interrupting/cancelled 就继续向下执行。相当于拿锁
if (!(state == NEW &&
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
// 是interrupt操作,要尝试打断执行任务的线程
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();
} finally { // final state
// interrupting过渡到最终 interrupted状态
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
// 善后工作,唤醒等待线程
finishCompletion();
}
return true;
}