futuretask通过状态机与volatile字段实现线程安全的结果传递:原子状态变更(cas)、outcome字段volatile保证可见性、get()采用自旋+阻塞双阶段等待,结果终态不可重置。

FutureTask 通过封装 Runnable 或 Callable 任务,配合内部状态机与阻塞等待机制,将异步执行结果安全地传递给调用线程。
核心机制:状态驱动 + 内存可见性保障
FutureTask 不是简单地“返回结果”,而是维护一个原子状态(NEW、COMPLETING、NORMAL、EXCEPTIONAL、CANCELLED、INTERRUPTING、INTERRUPTED),所有状态变更都通过 CAS 操作保证线程安全。结果值(outcome)被声明为 volatile 字段,确保 set() 写入的结果对 get() 调用线程立即可见。
当任务执行完成(正常或异常),FutureTask 会:
- 原子更新状态至 COMPLETING → NORMAL(成功)或 EXCEPTIONAL(异常)
- 将结果(返回值或异常)写入 volatile 的 outcome 字段
- 唤醒所有因 get() 阻塞在 WaitNode 链表上的线程
get() 如何获取结果:自旋 + 阻塞双阶段等待
调用 get() 时,FutureTask 先短暂自旋检查状态是否已完成(避免立即挂起),若未完成则进入阻塞等待:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 新建 WaitNode 并插入内部 waiters 链表(无锁栈结构)
- 调用 LockSupport.park() 挂起当前线程
- 任务完成后,由 finishCompletion() 遍历 waiters 并逐一 unpark
被唤醒后,get() 直接读取 volatile 的 outcome 字段——无需加锁,靠内存模型保证正确性。
结果传递的典型路径示例
以 Callable
- 构造 FutureTask:new FutureTask( () -> { Thread.sleep(100); return "done"; } )
- 提交执行:new Thread(task).start()
- 主线程调用 task.get() → 若未完成则 park;100ms 后任务结束 → outcome = "done" → 唤醒主线程 → get() 返回 "done"
- 若任务抛出异常,outcome 存储的是 ExecutionException 包装后的 Throwable,get() 会原样 rethrow
注意:结果只传递一次,且不可重置
FutureTask 的结果是终态的:
- get() 成功返回后,outcome 已确定,后续 get() 立即返回相同结果(不重复执行任务)
- 无法清空或重新设置结果;cancel() 仅中断执行,不改变已有的 outcome(除非尚未开始)
- 若需多次执行+结果复用,应新建 FutureTask 实例,而非复用已有对象
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










