futuretask 的 get() 在未完成时阻塞线程,基于 aqs 实现挂起/唤醒:通过 volatile state 控制生命周期,先入队再 park 防竞态,完成时批量 unpark;支持中断与超时,超时后需手动 isdone() 判断。

FutureTask 在未完成时调用 get() 会阻塞当前线程,其等待机制不是靠轮询消耗 CPU,而是基于 AQS(AbstractQueuedSynchronizer)构建的线程挂起与唤醒协作模型。核心在于状态驱动 + 等待队列 + LockSupport 配合。
state 状态字段控制等待逻辑
FutureTask 内部用一个 volatile 的 state 字段表示任务生命周期,取值包括:NEW(初始)、COMPLETING(正在完成)、NORMAL(正常结束)、EXCEPTIONAL(异常结束)、CANCELLED 等。get() 方法首先检查 state:若已 ≥ COMPLETING,说明结果已就绪或出错,直接返回 outcome 或抛异常;否则进入等待流程。
等待节点入队与线程挂起分步执行
当任务尚未完成,get() 会进入 awaitDone 循环,按顺序完成以下动作:
- 若
state == COMPLETING,调用Thread.yield()让出 CPU,避免立即挂起——适用于任务即将完成的短时场景 - 若还未创建等待节点,则新建
WaitNode并保存当前线程引用 - 若节点未入队,则将其加入 AQS 的同步等待队列尾部
- 最后才调用
LockSupport.park()挂起线程,使其进入WAITING状态,不占用 CPU
这种“先入队、再挂起”的设计,是为了防止竞态:避免刚判断完 state 为 NEW,另一线程立刻完成任务并清空等待队列,导致本线程入队后永远无法被唤醒。
任务完成时批量唤醒所有等待者
当任务执行结束(无论成功、异常或取消),run() 方法最终调用 finishCompletion():
- 将
outcome(结果或异常)写入成员变量 - 更新
state到对应终态(如NORMAL或EXCEPTIONAL) - 遍历 AQS 等待队列,对每个节点调用
LockSupport.unpark(node.thread)
被唤醒的线程重新竞争 AQS 锁,再次检查 state 是否已变更,确认完成后才返回结果或抛出 ExecutionException/InterruptedException。
支持中断与超时的阻塞安全机制
get() 的两种重载提供了可控等待能力:
-
get():可被中断。线程在 park 中收到 interrupt 信号时,立即抛InterruptedException,且不改变 task 的 state -
get(long, TimeUnit):底层调用LockSupport.parkNanos(),支持纳秒级超时。超时后自动返回,需手动调用isDone()判断是否真完成
注意:超时返回不等于任务终止,后台任务仍在运行;如需停止,必须显式调用 cancel(true)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











