FutureTask 通过 volatile int state 状态机、WaitNode 链表栈和 CAS 实现无锁异步控制;七种状态严格按四条路径流转,终态不可逆;get() 阻塞时压栈挂起,finishCompletion 批量唤醒;outcome 按 state 语义返回结果或封装异常。

FutureTask 的底层状态流转与阻塞唤醒机制,核心在于一个 volatile int state 状态机 + WaitNode 链表栈 + CAS 原子操作 的协同设计。它不依赖锁,而是用状态驱动行为、用链表管理等待线程、用 CAS 保证线程安全。
七种状态定义与合法流转路径
FutureTask 内部用单个 volatile 整型字段 state 编码全部生命周期,共 7 种状态:
- NEW(0):刚创建,尚未执行
-
COMPLETING(1):任务已结束,正将结果或异常写入
outcome字段(短暂中间态) -
NORMAL(2):正常完成,
outcome存放返回值 -
EXCEPTIONAL(3):执行抛出异常,
outcome存放 Throwable -
CANCELLED(4):调用
cancel(false)主动取消,未中断运行线程 -
INTERRUPTING(5):调用
cancel(true)时进入,正尝试中断 runner 线程 - INTERRUPTED(6):中断完成,runner 线程已响应中断
所有状态变更都严格遵循四条合法路径:
- NEW → COMPLETING → NORMAL
- NEW → COMPLETING → EXCEPTIONAL
- NEW → CANCELLED
- NEW → INTERRUPTING → INTERRUPTED
一旦进入 NORMAL / EXCEPTIONAL / CANCELLED / INTERRUPTED 这四种终态,state 就不可再变;COMPLETING 是唯一可被跳过的瞬态,仅用于保障 outcome 写入的原子性。
立即学习“Java免费学习笔记(深入)”;
get() 阻塞:基于 Treiber 栈的线程挂起
当调用 get() 时,若 state ≤ COMPLETING(即任务未完成),线程不会自旋,而是:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 构造一个
WaitNode节点(轻量级无锁节点) - 通过 CAS 将该节点压入
waiters指向的 Treiber 栈(无锁 LIFO 链表) - 调用
LockSupport.park()主动挂起当前线程
这个栈结构天然支持并发 push/pop,且无需同步开销。多个线程调用 get() 会形成一个等待链,但只在任务完成时统一唤醒——不是逐个 unpark,而是“唤醒全部”。
任务完成时的唤醒:一次性释放所有等待者
当 run() 执行完毕(无论成功或异常),或 cancel() 成功触发终态后,会执行 finishCompletion():
- 循环弹出
waiters栈中所有 WaitNode - 对每个节点对应的线程调用
LockSupport.unpark(node.thread) - 清空 waiters 引用(设为 null)
注意:唤醒动作发生在状态已变为终态之后,且是“fire-and-forget”式批量处理。被唤醒的线程在 park 返回后,会重新读取 state 并检查是否已完成,再决定是否继续等待或返回结果。
结果读取与异常封装:outcome 字段的双重语义
outcome 是一个非 volatile 的 Object 字段,但它受 state 读写保护:
- state == NORMAL → outcome 是计算返回值
- state == EXCEPTIONAL → outcome 是包装后的 ExecutionException(原始异常被封装在 cause 中)
- state == CANCELLED 或 INTERRUPTED →
get()抛出 CancellationException
report(int s) 方法根据 state 值统一提取并转换 outcome,确保调用方看到符合语义的返回或异常,屏蔽底层存储细节。

















