- 一、概述
- 1.1 FutureTask能够解决什么问题
- 1.2 FutureTask如何保证线程安全
- 二、关键知识点
- 三、状态分析
- 四、使用示例
- 五、源码分析
- 内部持有Callable类型变量,可以获取线程返回值
- 实现了Runnable接口,可以提交到线程池中运行,也可以直接被Thread执行
- 实现了Future接口,调用get时可以阻塞到获取结果,也可以提前取消任务
使用了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 callable = () -> {
Thread.sleep(100);
return 1;
};
private void futureAndExecutorService() throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
Future submit = executorService.submit(callable);
System.out.println(submit.get());
executorService.shutdown();
}
private void futureTaskAndThread() throws ExecutionException, InterruptedException {
FutureTask 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 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 FutureTaskimplements RunnableFuture { // 当前任务状态,是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; private Callable callable; private Object outcome; private volatile Thread runner; private volatile WaitNode waiters; @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); } public FutureTask(Callable callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; } public FutureTask(Runnable runnable, V result) { // 适配器模式,runnable转callable this.callable = Executors.callable(runnable, result); this.state = NEW; } public boolean isCancelled() { return state >= CANCELLED; } public boolean isDone() { return state != NEW; } 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); } 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() { } 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(); } } 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(); } } public void run() { // 启动时,状态必须是 NEW ,并且cas将runner代表的线程赋值为当前线程成功 if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return; try { Callable 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); } } protected boolean runAndReset() { if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return false; boolean ran = false; int s = state; try { Callable 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; } 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(); } } 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 } 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); } } 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); } } }



