futuretask采用locksupport.park/unpark,因其不依赖synchronized锁、支持线程级精准唤醒、允许unpark先于park调用避免通知丢失,且结合volatile+cas实现无锁等待链表,契合其状态机驱动、低开销、高并发的等待唤醒需求。

FutureTask 内部用 LockSupport.park() 和 LockSupport.unpark() 实现等待线程的挂起与唤醒,根本原因在于:它需要一种**不依赖锁、线程粒度精确、可提前唤醒、且能嵌入状态机**的阻塞机制 —— 而 wait/notify 或自旋都不满足这些要求。
为什么不用 synchronized + wait/notify?
wait/notify 必须在 synchronized 块内调用,会强制绑定对象监视器,带来额外开销和死锁风险;更重要的是,notify() 只能随机唤醒一个等待线程,无法精准唤醒正在 get() 的那个线程。FutureTask 允许多个线程并发调用 get(),但只应唤醒真正等待结果的那个线程 —— unpark(Thread) 正好支持这种一对一唤醒。
为什么不用自旋等待?
自旋(如 while(!isDone()) {})会持续占用 CPU,尤其在任务执行时间较长时极不经济。FutureTask 设计目标之一是“低开销等待”,park 会让线程进入 OS 级休眠(线程让出 CPU),直到被显式 unpark 或中断,资源利用率更高。
许可机制如何适配 FutureTask 状态流转?
FutureTask 内部用 volatile int state 标识任务生命周期(NEW → COMPLETING → NORMAL/EXCEPTIONAL 等)。当线程调用 get() 时:
- 若 state 还是 NEW,说明结果未就绪,线程就调用
LockSupport.park(this)挂起自己; - 任务执行完毕后,在
set()或setException()中,遍历内部WaitNode链表,对每个等待线程调用LockSupport.unpark(waiter.thread); - 由于 park/unpark 基于“许可”(permit),即使 unpark 先于 park 执行,后续 park 也能立即返回 —— 这让 FutureTask 不必担心唤醒丢失,也无需加锁同步唤醒时机。
WaitNode 链表 + unpark 是怎么协作的?
FutureTask 维护一个无锁的等待节点链表 volatile WaitNode waiters,每个 WaitNode 记录当前等待线程和下一个节点。当新线程进入 get() 并发现未完成时,它会用 CAS 将自己头插进该链表,再 park;任务结束时,再遍历链表逐个 unpark。整个过程不依赖 synchronized 或 ReentrantLock,仅靠 volatile + CAS + park/unpark 就实现了安全、轻量、可扩展的等待通知模型。










