一、概述
1.1 FutureTask能够解决什么问题
- 内部持有Callable类型变量,可以获取线程返回值
- 实现了Runnable接口,可以提交到线程池中运行,也可以直接被Thread执行
- 实现了Future接口,调用get时可以阻塞到获取结果,也可以提前取消任务
1.2 FutureTask如何保证线程安全
使用了cas
二、关键知识点
- 状态的含义以及转移方式(set、setException)
- 任务启动调用了run方法,run的内部逻辑
- 想要获取任务结果的线程调用get方法被阻塞,其阻塞逻辑(awaitDone)
- 阻塞等待队列的添加、移除(removeWaiter)、唤醒(finishCompletion)逻辑
- cancel逻辑
三、状态分析
一个FutureTask任务有七种状态,每种状态含义以及状态转换图如下
状态 | 对应值 | 含义 | 前一状态 |
---|---|---|---|
NEW | 0 | 新的任务 或者 还没被执行完的任务,是初始状态 | |
COMPLETING | 1 | 中间态-完成call逻辑。任务已经执行完成 或者 发生异常,但异常还没保存到outcome。state > COMPLETING 代表任务已完成(正常完成,执行异常,被取消) | NEW |
NORMAL | 2 | 最终态-完成。任务执行完成,且执行结果保存到outcome字段。 | COMPLETING |
EXCEPTIONAL | 3 | 最终态-发生异常。执行发生异常并将异常信息保存到outcome字段。 | COMPLETING |
CANCELLED | 4 | 最终态-取消任务。任务处在NEW状态时,用户调用了cancel(false)方法,取消任务且 不中断任务执行线程 | NEW |
INTERRUPTING | 5 | 中间态-中断中。任务处在NEW状态,用户调用了cancel(true)方法,取消任务并且想要中断任务线程但还没中断线程之前 | NEW |
INTERRUPTED | 6 | 最终态-已中断。任务处在INTERRUPTING,在执行完interrupted()后,线程被中断 | INTERRUPTING |
四、使用示例
三种使用方式:
- FutureTask + Thread
- FutureTask + ExecutorService
- Future + ExecutorService
代码如下:
public class FutureTaskTest {
static final Callable<Integer> callable = () -> {
Thread.sleep(100);
return 1;
};
private void futureAndExecutorService() throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
Future<Integer> submit = executorService.submit(callable);
System.out.println(submit.get());
executorService.shutdown();
}
private void futureTaskAndThread() throws ExecutionException, InterruptedException {
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread thread = new Thread(futureTask);
thread.start();
System.out.println(futureTask.get());
}
private void futureTaskAndExecutorService() throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
FutureTask<Integer> futureTask = new FutureTask<>(callable);
executorService.submit(futureTask);
System.out.println(futureTask.get());
executorService.shutdown();
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTaskTest task = new FutureTaskTest();
task.futureTaskAndThread();
task.futureTaskAndExecutorService();
task.futureAndExecutorService();
}
}
五、源码分析
package java.util.concurrent;
import java.util.concurrent.locks.LockSupport;
public class FutureTask<V> implements RunnableFuture<V> {
/**
* <img src="./img/FutureTask状态图.png" />
*/
// 当前任务状态,是volatile类型
private volatile int state;
// 新的任务 或者 还没被执行完的任务,是初始状态
private static final int NEW = 0;
// state > COMPLETING 代表任务已完成(正常完成,执行异常,被取消)
// 中间态-完成。任务已经执行完成 或者 发生异常,但异常还没保存到outcome。中间态,比较短 NEW->COMPLETING
private static final int COMPLETING = 1;
// 最终态-完成。任务执行完成,且执行结果保存到outcome字段。从COMPLETING->NORMAL
private static final int NORMAL = 2;
// 最终态-发生异常。执行发生异常并将异常信息保存到outcome字段。从从COMPLETING->EXCEPTIONAL
private static final int EXCEPTIONAL = 3;
// 最终态-取消任务。任务处在NEW状态时,用户调用了cancel(false)方法,取消任务且 不中断任务执行线程 NEW->CANCELLED
private static final int CANCELLED = 4;
// 中间态-中断中。任务处在NEW状态,用户调用了cancel(true)方法,取消任务并且想要中断任务线程但还没中断线程之前 NEW->INTERRUPTING
private static final int INTERRUPTING = 5;
// 最终态-已中断。任务处在INTERRUPTING,在执行完interrupted()后,线程被中断,状态转换 INTERRUPTING->INTERRUPTED
private static final int INTERRUPTED = 6;
/**
* 内部持有的callable任务,运行后清空
*/
private Callable<V> callable;
/**
* get中返回的结果或者抛出的异常
* 不是volatile类型,被state的读写保护
*/
private Object outcome;
/**
* 运行callable的线程
*/
private volatile Thread runner;
/**
* 使用Treiber栈保存线程
*/
private volatile WaitNode waiters;
/**
* 返回结果或者抛出异常
* @param s 最终完成的状态
*/
@SuppressWarnings("unchecked")
private V report(int s) throws ExecutionException {
Object x = outcome;
// 正常结束,则返回结果
if (s == NORMAL)
return (V)x;
// 大于等于CANCELLED(事实上只有CANCELLED,两个中断状态在进入该方法前就抛出了异常)
if (s >= CANCELLED)
throw new CancellationException();
// EXCEPTIONAL状态抛出异常
throw new ExecutionException((Throwable)x);
}
/**
* 构造
* @param callable callable接口
*/
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW;
}
/**
* 构造,这里用了适配器模式,将runnable转成callable
* @param runnable runnable
* @param result 记录执行结果
*/
public FutureTask(Runnable runnable, V result) {
// 适配器模式,runnable转callable
this.callable = Executors.callable(runnable, result);
this.state = NEW;
}
/**
* INTERRUPTING(5)、INTERRUPTED(6)、CANCELLED(4) 都是调用cancelled方法后的状态
* @return 是否
*/
public boolean isCancelled() {
return state >= CANCELLED;
}
/**
* 除了new都是任务已完成
* @return 是否
*/
public boolean isDone() {
return state != NEW;
}
/**
* 取消任务,必须在NEW状态才可以
* 任务取消后,被阻塞的线程会被唤醒,得到get返回null
* @param mayInterruptIfRunning 是否中断
* @return 是否取消成功
*/
public boolean cancel(boolean mayInterruptIfRunning) {
// 如果不是NEW状态或者cas更改状态失败,则返回false
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;
// 如果t不为null,则中断执行任务的线程t
if (t != null)
t.interrupt();
} finally { // final state
// 将状态最终变为INTERRUPTED
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
// 如果不中断直接执行,则唤醒所有等待线程
finishCompletion();
}
return true;
}
/**
* 获取结果,任务未结束前调用线程被阻塞
*/
public V get() throws InterruptedException, ExecutionException {
int s = state;
// 假如状态为NEW或者COMPLETING,则阻塞在这里
if (s <= COMPLETING)
s = awaitDone(false, 0L);
// 返回结果或抛出异常
return report(s);
}
/**
* 阻塞指定时间
* @param timeout 阻塞时间
* @param unit 单位
* @return 任务结果
*/
public V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
if (unit == null)
throw new NullPointerException();
int s = state;
// 超时返回的状态一定小于COMPLETING
if (s <= COMPLETING &&
(s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
throw new TimeoutException();
return report(s);
}
/**
* 可以被子类重写,在唤醒所有线程后调用
*/
protected void done() { }
/**
* 状态变更,记录执行结果到outcome上,并唤醒所有线程
* @param v 执行结果
*/
protected void set(V v) {
// 状态从NEW->COMPLETING
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
// 执行结果赋值到outcome
outcome = v;
// 将状态从COMPLETING->NORMAL
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
// 唤醒所有等待线程
finishCompletion();
}
}
/**
* 执行失败抛出异常后调用此方法
* @param t 捕获的异常
*/
protected void setException(Throwable t) {
// 将NEW->COMPLETING 中间态
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
// 记录异常信息到outcome
outcome = t;
// 将状态变为COMPLETING->EXCEPTIONAL
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL);
// 唤醒所有等待的线程
finishCompletion();
}
}
/**
* 线程启动时调用的方法
* 启动时,状态必须是NEW
* callable为null的话不报错,不执行
* 执行一次后就不能再调用run方法了
*/
public void run() {
// 启动时,状态必须是 NEW ,并且cas将runner代表的线程赋值为当前线程成功
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
// callable不为null且状态为NEW的时候
if (c != null && state == NEW) {
V result;
// 逻辑执行状态标记
boolean ran;
try {
// 执行call逻辑,记录结果
result = c.call();
// 设置执行结果成功
ran = true;
} catch (Throwable ex) {
result = null;
// 设置执行结果失败
ran = false;
// 更改状态,并唤醒所有等待的线程
setException(ex);
}
// 如果执行成功
if (ran)
// 状态变更,记录执行结果到outcome上,并唤醒所有线程
set(result);
}
} finally {
// 为了防止并发调用run方法,在state变成最终态之前,runner必须不是null
runner = null;
int s = state;
// 如果发现被取消并中断了
if (s >= INTERRUPTING)
// 让调用cancelled的线程先执行,直到将状态变成INTERRUPTED
handlePossibleCancellationInterrupt(s);
}
}
/**
* 与run方法基本相同,不过该方法可以重复调用,
* 如果无异常、取消、中断,state不会被更新,一直保持为NEW。
*/
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 = null;
s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
return ran && s == NEW;
}
/**
* 保证run或runAndReset方法在cancelled(true)方法结束后结束
* 当发现状态为INTERRUPTING的时候,让出cpu资源,直到cancelled把状态变为INTERRUPTED
*/
private void handlePossibleCancellationInterrupt(int s) {
if (s == INTERRUPTING)
while (state == INTERRUPTING)
Thread.yield();
}
/**
* 单链表
*/
static final class WaitNode {
volatile Thread thread;
volatile WaitNode next;
WaitNode() { thread = Thread.currentThread(); }
}
/**
* 唤醒所有等待的线程(唤醒后在awaitOne中继续执行),执行done方法,callable属性重新赋值为null
*/
private void finishCompletion() {
// assert state > COMPLETING;
// cas重试
for (WaitNode q; (q = waiters) != null;) {
// 将waiters头结点从指向q变成指向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
}
/**
* 等待任务执行完成 或者 中断 或者 超时
* 状态为NEW的节点被阻塞
* 被唤醒后,
* 如果中断,则移除等待队列并抛出异常
* 如果处于COMPLETING状态,逻辑执行完但还没将结果放到outcome,则让出CPU
* 如果大于COMPLETING状态,相当于CANCELLED、NORMAL、EXCEPTIONAL,则返回状态
* @param timed true 则等待,false不等待
* @param nanos time 如果timed为true,则等待nanos时长
* @return 完成后的state
*/
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
// 等待结束时间
final long deadline = timed ? System.nanoTime() + nanos : 0L;
// 当前等待线程包装成的等待节点
WaitNode q = null;
// 当前节点是否进入了等待队列
boolean queued = false;
// 自旋
for (;;) {
// 获取并清除中断状态。如果已经中断了,则移除节点并抛出异常
// cancelled(true)后,会在这个方法结束
if (Thread.interrupted()) {
// 移除等待的waitNode
removeWaiter(q);
throw new InterruptedException();
}
// 获取当前状态
int s = state;
// 如果状态大于COMPLETING,说明任务处于最终态或者中断中
// cancelled(false)后,会在这个方法结束
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
// 任务执行完了,但还没将结果放到outcome中,让出当前CPU,让执行任务的线程调用run方法使用CPU
else if (s == COMPLETING) // cannot time out yet
Thread.yield();
// 如果状态为NEW,并且q为null,则让q指向新建的等待节点
else if (q == null)
q = new WaitNode();
// 如果状态为NEW,并且q不为null,并且queued为false,也就是当前节点没进入等待队列。
else if (!queued)
// 头插法,当前节点的后继为原来的头,并且将头指向当前节点,返回cas是否成功
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
// 如果状态为NEW,并且q不为null,queued为true,并设置了阻塞等待时间
else if (timed) {
nanos = deadline - System.nanoTime();
// 如果超时了
if (nanos <= 0L) {
// 移除队列中的节点q
removeWaiter(q);
// 返回当前状态
return state;
}
LockSupport.parkNanos(this, nanos);
}
//如果状态为NEW,并且q不为null,queued为true,并且没设置阻塞时间,则直接阻塞
else
// 阻塞当前线程
LockSupport.park(this);
}
}
/**
* 将node的thread置为null,并移除等待队列中thread为null的节点
* @param node 被移除的节点
*/
private void removeWaiter(WaitNode node) {
if (node != null) {
// node拥有的线程变为null
node.thread = null;
retry:
for (;;) { // restart on removeWaiter race
for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
// s为q的后继
s = q.next;
// 如果q拥有的thread不是null
if (q.thread != null)
// 历史节点变为q
pred = q;
// 如果q拥有的thread是null(说明q是应该被移除的节点) 且 历史节点不为null(q不是头结点)
else if (pred != null) {
// q的前驱的后继指向q的后继,说明q移除了队列
pred.next = s;
// 如果pred拥有的线程变为null,说明pred的节点应该被移除
if (pred.thread == null) // check for race
// 外层循环执行continue,内层停止循环。又要从头开始走一次循环,目的将pred也移除队列
continue retry;
}
// 如果q拥有的线程为null,并且pred为null(说明q为头结点,并且是应该被移除的节点)
// cas将waiter(也就是头结点)指向s(q的后继),相当于将node节点出队了
else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,
q, s))
continue retry;
}
// 假如遍历到结尾,也不存在thread为null的节点,则停止循环
break;
}
}
}
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE;
private static final long stateOffset;
private static final long runnerOffset;
private static final long waitersOffset;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> k = FutureTask.class;
stateOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("state"));
runnerOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("runner"));
waitersOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("waiters"));
} catch (Exception e) {
throw new Error(e);
}
}
}