completablefuture核心是任务启动、结果存储、回调触发三条主线:通过volatile字段result存值、stack/completions存回调链、waiters存阻塞线程;用treiber栈+状态机+回调链实现无锁异步。

分析 CompletableFuture 源码,关键不是逐行通读,而是抓住三条主线:任务如何启动、结果如何存储、回调如何触发。它不是靠轮询或线程挂起等待,而是用无锁栈 + 状态机 + 回调链驱动整个异步流程。
看核心字段:result、stack(或 completions)、waiters
这三个 volatile 字段是理解行为的起点:
- result:直接存最终值或 AltResult(包装异常或 null)。完成即写入,后续所有 get/join/thenXXX 都基于它判断状态
-
stack / completions:JDK 8–17 多数版本用
volatile Completion stack;部分 JDK 版本(如某些 17+)改用volatile CompletionNode completions。本质都是 Treiber 栈——后进先出的无锁单链表,用于存放待执行的回调任务(如 thenApply、whenComplete 的封装体) -
waiters:同样是 Treiber 栈,节点是 WaitNode,对应调用
get()、join()等阻塞方法的线程。线程 park 在这里,等 result 写入后被 unpark 唤醒
抓关键内部类:Completion、UniCompletion、WaitNode
它们定义了“谁来执行”和“怎么唤醒”:
-
Completion 是抽象基类,继承 ForkJoinTask 且实现 Runnable,保证可被线程池调度;含
next字段构成回调链 -
UniCompletion 是最常用子类(如 thenApply 对应 UniApply),携带三个关键引用:
src(源 CompletableFuture)、dep(目标 CompletableFuture)、executor(指定线程池,null 则由触发线程同步执行) -
WaitNode 不是普通节点,它实现了
ForkJoinPool.ManagedBlocker,其isReleasable()控制 park/unpark 逻辑:检查 thread 是否为空(已被唤醒)、是否中断、是否超时,决定是否退出阻塞
理清执行入口:tryFire、postComplete、complete
回调不是自动运行的,而是靠“完成传播”驱动:
-
complete(value) 或 completeExceptionally(ex):手动设置结果,会调用
postComplete() -
postComplete():核心传播函数。先尝试用
tryFire(SYNC)同步执行栈顶回调;若失败(比如 executor 不为空),则用tryFire(ASYNC)提交到线程池;执行完一个后,顺着next链继续处理下一个 -
tryFire(mode):真正执行回调的入口。mode 决定执行方式:
SYNC(当前线程立即执行)、ASYNC(提交给 executor)、NESTED(嵌套在另一个 postComplete 中)
验证典型链路:supplyAsync → thenApply → join
走一遍这个最小闭环,能串起全部机制:
-
supplyAsync创建 CompletableFuture,提交 Supplier 到 ForkJoinPool.commonPool(),任务完成后调用complete(value) -
thenApply不立刻执行,而是构造一个 UniApply 实例,压入src.stack(Treiber 栈 push) -
complete触发postComplete,遍历栈中所有 Completion,对每个调用tryFire(ASYNC)—— 若指定了 executor 就提交,否则由完成任务的线程同步执行 -
join()检查result != null,否则新建 WaitNode 并 push 到waiters栈,再调用LockSupport.park阻塞;等complete写入 result 后,postComplete会顺带 unpark 所有 waiters
不复杂但容易忽略:CompletableFuture 的“异步性”不在创建时,而在回调触发时机;它的高效来自无锁栈结构与状态一次写入,而非多线程争抢。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











