FutureTask

FutureTask 源码分析

FutureTask 是”一次异步计算”的结果容器:把 Callable 包装成可以丢给线程执行的任务,调用方随时 get() 阻塞取结果、cancel() 取消。
它不用锁,核心是一个 volatile int state 状态机——CAS 保证结果只发布一次,Treiber 栈(无锁链栈)挂起等结果的线程。
线程池 submit() 返回的 Future,默认实现就是它。

// 基于本地 JDK 源码仓 (java.base, JDK 19+ 版本, 含 MhUtil), java.util.concurrent.FutureTask
public class FutureTask<V> implements RunnableFuture<V> {   // RunnableFuture = Runnable + Future:既能被 execute,又能被 get

    // 七态状态机。合法迁移只有四条路径,> COMPLETING 即尘埃落定:
    // NEW -> COMPLETING -> NORMAL          正常出结果
    // NEW -> COMPLETING -> EXCEPTIONAL     任务抛了异常
    // NEW -> CANCELLED                     cancel(false)
    // NEW -> INTERRUPTING -> INTERRUPTED   cancel(true)
    private volatile int state;
    private static final int NEW          = 0;
    private static final int COMPLETING   = 1;  // 瞬时态:outcome 正在写入的窗口期
    private static final int NORMAL       = 2;
    private static final int EXCEPTIONAL  = 3;
    private static final int CANCELLED    = 4;
    private static final int INTERRUPTING = 5;  // 瞬时态:cancel(true) 正在发中断
    private static final int INTERRUPTED  = 6;

    private Callable<V> callable;               // 任务结束后置 null,减小内存占用
    private Object outcome; // non-volatile, protected by state reads/writes    结果或异常,故意不加 volatile(见串讲)
    private volatile Thread runner;             // 正在执行任务的线程,run() 里 CAS 占坑
    private volatile WaitNode waiters;          // 等 get() 的线程组成的 Treiber 栈(头插无锁栈)

    // 终态之后把 outcome 翻译成三种结局:返回值 / CancellationException / ExecutionException
    @SuppressWarnings("unchecked")
    private V report(int s) throws ExecutionException {
        Object x = outcome;
        if (s == NORMAL)
            return (V)x;
        if (s >= CANCELLED)             // 状态值是按序精心排的:>= CANCELLED 的三个态都算"被取消"
            throw new CancellationException();
        throw new ExecutionException((Throwable)x);
    }

    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable    volatile 写压轴,顺带把 callable 安全发布出去
    }

    public boolean isCancelled() {
        return state >= CANCELLED;
    }

    public boolean isDone() {
        return state != NEW;    // 注意 COMPLETING 也算 done——所以 awaitDone 里见到 COMPLETING 不许空手返回
    }

    // 取消:只有还停在 NEW 的任务才有机会。mayInterruptIfRunning 决定走 CANCELLED 还是 INTERRUPTING 路线
    public boolean cancel(boolean mayInterruptIfRunning) {
        if (!(state == NEW && STATE.compareAndSet
              (this, 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();          // 只是"请求"停止,call() 不响应中断就停不下来
                } finally { // final state
                    STATE.setRelease(this, INTERRUPTED);
                }
            }
        } finally {
            finishCompletion(); // 不管哪条路线,都要唤醒所有等 get 的线程
        }
        return true;
    }

    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)            // NEW 或 COMPLETING 都还没法读 outcome,去等
            s = awaitDone(false, 0L);
        return report(s);
    }

    // ... 省略 get(timeout, unit) / resultNow / exceptionNow / state() / done()

    // run() 成功后调用:发布结果。CAS NEW->COMPLETING 是进入完成流程的唯一门票
    protected void set(V v) {
        if (STATE.compareAndSet(this, NEW, COMPLETING)) {
            outcome = v;                        // 普通写。此刻 state=COMPLETING,没有任何读方会碰 outcome
            STATE.setRelease(this, NORMAL); // final state      release 写:保证 outcome 先于 state 对外可见
            finishCompletion();
        }
    }

    // 任务抛异常时的发布路径,结构与 set 完全对称,outcome 存的是 Throwable
    protected void setException(Throwable t) {
        if (STATE.compareAndSet(this, NEW, COMPLETING)) {
            outcome = t;
            STATE.setRelease(this, EXCEPTIONAL); // final state
            finishCompletion();
        }
    }

    public void run() {
        if (state != NEW ||
            !RUNNER.compareAndSet(this, null, Thread.currentThread()))
            return;             // CAS runner 占坑失败 = 已有线程在跑,防止同一任务被并发执行
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {    // 再查一次 state:占坑期间可能已被 cancel
                V result;
                boolean ran;
                try {
                    result = c.call();          // 真正干活的地方
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);           // 异常不往外抛,存进 outcome——线程池里任务异常"无声"的根源
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;      // 必须等 state 定局才清,否则空窗期另一线程能 CAS 占坑重跑
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

    // 确保 cancel(true) 的中断只落在本任务执行期间,不泄漏给 worker 线程的下一个任务
    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   自旋等 cancel 线程把中断发完
        // ... 省略注释:不清中断标志,因为无法区分"取消中断"和"业务自己用的中断"
    }
}
// 基于本地 JDK 源码仓 (java.base, JDK 19+ 版本), java.util.concurrent.FutureTask —— 等待与唤醒机制
    // Treiber 栈节点:比 AQS 节点简单得多,只记线程 + next
    static final class WaitNode {
        volatile Thread thread;
        volatile WaitNode next;
        WaitNode() { thread = Thread.currentThread(); }
    }

    // 终态后收尾:整棵摘下等待栈逐个唤醒 -> done() 钩子 -> 扔掉 callable
    private void finishCompletion() {
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) {
            if (WAITERS.weakCompareAndSet(this, q, null)) {     // 一次 CAS 摘走整个栈,后来者见 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();                 // 模板方法,ExecutorCompletionService 就是覆盖它把完成任务塞进队列

        callable = null;        // to reduce footprint
    }

    // get 的等待主体:无锁自旋状态机,每圈根据观察到的 state 推进一步
    private int awaitDone(boolean timed, long nanos)
        throws InterruptedException {
        // ... 省略原注释:精确控制 nanoTime 调用次数与溢出边界
        long startTime = 0L;    // Special value 0L means not yet parked
        WaitNode q = null;
        boolean queued = false;
        for (;;) {
            int s = state;
            if (s > COMPLETING) {           // 尘埃落定,返回终态
                if (q != null)
                    q.thread = null;
                return s;
            }
            else if (s == COMPLETING)
                // We may have already promised (via isDone) that we are done
                // so never return empty-handed or throw InterruptedException
                Thread.yield();             // 只差最后一笔 outcome,自旋让步比 park 便宜;且 isDone 已承诺完成,不能抛中断
            else if (Thread.interrupted()) {
                removeWaiter(q);            // 从栈里摘掉自己的节点再抛,避免留垃圾
                throw new InterruptedException();
            }
            else if (q == null) {           // 第一圈:先建节点,还不入栈
                if (timed && nanos <= 0L)
                    return s;
                q = new WaitNode();
            }
            else if (!queued)               // 第二圈:Treiber 头插——先挂 next 再 CAS 头指针
                queued = WAITERS.weakCompareAndSet(this, q.next = waiters, q);
            else if (timed) {
                final long parkNanos;
                if (startTime == 0L) { // first time
                    startTime = System.nanoTime();
                    if (startTime == 0L)
                        startTime = 1L;
                    parkNanos = nanos;
                } else {
                    long elapsed = System.nanoTime() - startTime;
                    if (elapsed >= nanos) {
                        removeWaiter(q);
                        return state;       // 超时返回当前 state,由调用方判定抛 TimeoutException
                    }
                    parkNanos = nanos - elapsed;
                }
                // nanoTime may be slow; recheck before parking
                if (state < COMPLETING)
                    LockSupport.parkNanos(this, parkNanos);
            }
            else
                LockSupport.park(this);     // 第三圈起:真正挂起,等 finishCompletion 的 unpark
        }
    }

    // ... 省略 removeWaiter:无锁遍历摘除失效节点,撞上竞争就整条重扫

原理串讲

从线程池视角走一遍完整链路。pool.submit(callable) 在 AbstractExecutorService 里干两件事:newTaskFor(callable) 把 Callable 包成 FutureTask,然后 execute(ftask) 丢进池子——submit 返回的 Future 和 worker 线程要跑的 Runnable 是同一个对象,这就是 FutureTask 实现 RunnableFuture 的意义。
worker 线程调 run(),先 CAS 把 runner 从 null 换成自己:这个占坑保证同一个任务不会被两个线程并发执行(Treiber 栈和状态机都只按”单一 runner”设计)。
然后 c.call() 真正执行,成功走 set(result),抛异常走 setException(ex)

发布结果是三步曲:CAS(NEW→COMPLETING)、普通写 outcomesetRelease 终态。
为什么要 COMPLETING 这个中间态?因为 outcome 不是 volatile,写它和写终态 state 是两个动作,必须保证任何读方在看到终态之前绝不去读 outcome——COMPLETING 就是”结果正在写、谁都别碰”的隔离窗口,get 端见到它只会 yield 自旋。

代码块JAVA · 2 行收起展开
为什么 outcome 不加 volatile 也安全?靠 state 建立 happens-before:写方 `setRelease(NORMAL)` 是 release 写,保证之前的 `outcome = v` 先行发布;读方 `report()` 之前必然读过 volatile state(acquire 语义)并看到了终态,于是 outcome 的写对它可见。
这条链省掉了 outcome 上的 volatile 开销;而终态用 setRelease 而非完整 volatile 写,是因为终态值唯一且不再变更,不需要 StoreLoad 全屏障。

get 端:get() 读到 state <= COMPLETING 就进 awaitDone,那个 for(;;) 每圈只推进一步——建节点、CAS 头插入 waiters 栈、park——把”检查状态”和”入队挂起”拆成多圈重试,是为了每一步之后都能重新观察 state,任何时刻任务完成都能立刻返回而不是白白挂起。
任务定局后 finishCompletion 用一次 CAS 把整个栈摘下来逐个 unpark,被唤醒的线程回到循环顶部读到终态返回,最后 report(s) 按 NORMAL/EXCEPTIONAL/CANCELLED 三分天下。

cancel 端和 run 端在 NEW 上赛跑:cancel 的 CAS 和 set/setException 的 CAS 抢的是同一个 NEW,谁赢谁定终局。
cancel(false) 只是把状态打成 CANCELLED——正在跑的 call() 会继续跑完,只是 set 里的 CAS 必然失败、结果作废。
cancel(true) 拆成 INTERRUPTING→interrupt→INTERRUPTED 两段,为什么不一步到位?因为 run() 的 finally 需要一个可观察的信号:runner = null 之后重读 state,发现 >= INTERRUPTING 就调 handlePossibleCancellationInterrupt 自旋等到 INTERRUPTED——即等 cancel 线程把 interrupt 发完再让 run() 返回。
否则中断可能在 run() 返回之后才送达,落在 worker 线程的下一个任务头上(leaked interrupt)。
类注释里的 revision notes 也点明了老版本基于 AQS、正是因为取消竞争下的中断残留问题才改成现在的 state + Treiber 栈方案。

设计取舍

  • outcome 不用 volatile:靠 state 的 release 写 / volatile 读配对建立 happens-before,COMPLETING 隔离写入窗口,是这个类最精妙的设计。
  • cancel(true) 不保证任务停下:interrupt 只是请求,call() 里不检查中断、不碰可中断阻塞,任务照跑;cancel(false) 更是只作废结果。
  • cancel 成功后 get() 永远抛 CancellationException——哪怕 call() 其实跑完了并算出了结果,结果也被丢弃。
  • submit 会”吞异常”:异常被 setException 存进 outcome,不调 get() 就永远看不到;对比 execute(Runnable) 会走 UncaughtExceptionHandler。
  • 等待结构用 Treiber 栈而非 AQS:场景只有”一次性完成、全体唤醒”,无需公平性和独占/共享语义,栈的无锁头插最简单,还绕开了 AQS 方案的中断残留问题。

延伸阅读