FutureTask线程安全依赖volatile变量+CAS+无锁等待队列:volatile state保障状态可见性与有序性,CAS确保状态转换原子性,WaitNode栈实现无锁等待与LIFO唤醒,volatile outcome和runner借助happens-before保证数据读写顺序。

FutureTask 的线程安全不是靠锁实现的,而是依赖 volatile 变量 + CAS 操作 + 无锁等待队列协同保障。核心在于状态变更、结果写入和等待线程管理这三个关键环节全部避开传统互斥锁。
volatile 状态字段 state 是线程安全的基石
FutureTask 内部用一个 volatile int state 表示任务生命周期,例如 NEW、NORMAL、EXCEPTIONAL、CANCELLED 等。volatile 保证了:
- 所有线程对 state 的读写都直接操作主内存,不缓存到本地工作内存
- state 的修改具有可见性,一个线程更新后,其他线程能立即感知
- 配合 CAS(如 compareAndSetState),可原子地判断并更新状态,避免竞态
CAS 操作确保状态转换的原子性
FutureTask 在 run() 执行开始前、set() 设置结果、setException() 处理异常、cancel() 尝试取消等关键路径上,都使用 CAS 修改 state。例如:
- 执行前检查:仅当 state == NEW 时才允许设置 runner 并进入计算逻辑
- 完成时写入:只有在 state 为 COMPLETING 阶段,才能通过 CAS 转为 NORMAL 或 EXCEPTIONAL
- 取消时防护:cancel(true) 会尝试将 state 从 NEW → CANCELLED,失败说明已被其他线程抢先完成或取消
这种“先比较再设置”的模式,天然支持多线程并发调用 run()、get()、cancel() 而不出现状态错乱。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
WaitNode 构成的栈式等待队列是无锁唤醒的关键
多个线程同时调用 get() 且任务未完成时,它们不会自旋空耗 CPU,而是被封装为 WaitNode 节点,以 CAS 方式压入 waiters 栈顶:
- waiters 是 volatile WaitNode 引用,指向当前等待链表的头节点
- 每个 WaitNode 包含 thread 字段(阻塞的线程)和 next 指针(指向下一个等待节点)
- 入栈和出栈均通过 CAS 更新 waiters,无需加锁,也无 AQS 的复杂队列管理
- 任务完成时,FutureTask 会遍历整个 waiters 栈,逐个 unpark 对应线程,唤醒顺序是 LIFO(后进先出)
outcome 和 runner 字段同样依赖 volatile + happens-before 语义
结果 outcome 和执行线程 runner 都是 volatile 修饰:
- runner 的写入发生在任务真正开始执行时,volatile 保证其他线程看到非 null runner 即意味着任务已启动
- outcome 的写入严格发生在 state 变更为 NORMAL/EXCEPTIONAL 之后,借助 volatile 写的 happens-before 效果,确保 get() 线程读到 outcome 时,其值一定已正确写入
- 这种“状态先行、数据后置”的设计,让读写天然有序,不需要额外同步

















