CompletableFuture 源码深度解析:WaitNode、CompletionNode 与 Completion 回调机制
CompletableFuture 是 Java 8 引入的功能强大的异步编程工具,既可以像 Future 一样阻塞等待结果,也支持非阻塞的回调链式编程。
在它的源码内部,等待机制与回调机制的核心支撑,正是以下三个关键结构:
- WaitNode:管理阻塞等待的线程
- CompletionNode:管理回调任务
- Completion:回调任务的抽象基类
本文将直接从 JDK 源码出发,逐行分析这三者的设计与实现原理。
1. 关键成员变量
在 CompletableFuture 内部,和等待、回调相关的核心字段有三个:
volatile Object result; // 任务结果或异常包装对象(AltResult)
volatile WaitNode waiters; // Treiber 栈,保存等待线程
volatile CompletionNode completions; // Treiber 栈,保存回调任务
1.1 result
- 保存任务完成后的状态。
- 如果是正常完成,直接保存结果值。
- 如果是异常完成,保存的是 AltResult(内部类)用于封装异常。
1.2 waiters
- 保存所有调用
get()、join()等需要阻塞等待的线程。 - 使用 Treiber 栈(无锁单链表)存储,每个节点是一个
WaitNode。
1.3 completions
- 保存所有在任务完成后需要触发的回调任务。
- 也是 Treiber 栈结构,每个节点是
CompletionNode,内部封装了一个Completion对象。
2. WaitNode —— 阻塞线程的管理
源码:
static final class WaitNode implements ForkJoinPool.ManagedBlocker {
long nanos; // 等待时间(纳秒),仅定时等待时使用
final long deadline; // 截止时间(纳秒时间戳),仅定时等待时使用
volatile int interruptControl; // >0 可中断, <0 已中断
volatile Thread thread; // 等待的线程
volatile WaitNode next; // Treiber 栈指针
WaitNode(boolean interruptible, long nanos, long deadline) {
this.thread = Thread.currentThread();
this.interruptControl = interruptible ? 1 : 0;
this.nanos = nanos;
this.deadline = deadline;
}
public boolean isReleasable() {
if (thread == null)
return true; // 已唤醒
if (Thread.interrupted()) {
int i = interruptControl;
interruptControl = -1;
if (i > 0)
return true; // 响应中断
}
if (deadline != 0L &&
(nanos <= 0L || (nanos = deadline - System.nanoTime()) <= 0L)) {
thread = null; // 超时
return true;
}
return false;
}
public boolean block() {
if (isReleasable())
return true;
else if (deadline == 0L)
LockSupport.park(this); // 无限等待
else if (nanos > 0L)
LockSupport.parkNanos(this, nanos); // 定时等待
return isReleasable();
}
}
2.1 设计特点
-
实现了
ForkJoinPool.ManagedBlocker
这意味着当 CompletableFuture 运行在 ForkJoinPool 中时,阻塞不会过度占用线程池的并行度。
ForkJoinPool 会在阻塞时可能补充额外的线程。 -
中断控制
interruptControl通过 >0 / <0 来标识当前节点是否支持中断,以及是否已被中断。 -
Treiber 栈结构
WaitNode.next构成无锁链表,通过 CAS 入栈和出栈,避免锁竞争。
3. CompletionNode —— 回调任务的节点
源码:
static final class CompletionNode {
final Completion completion; // 回调任务对象
volatile CompletionNode next; // Treiber 栈指针
CompletionNode(Completion completion) {
this.completion = completion;
}
}
3.1 作用
CompletionNode 是 completions 栈的节点,它不像 WaitNode 保存线程,而是保存一个 回调任务,任务的类型是 Completion 抽象类的子类。
当 CompletableFuture 完成时,postComplete() 方法会遍历 completions 栈中的所有节点,依次触发它们的 tryFire() 方法来执行回调。
4. Completion —— 回调任务的抽象基类
源码(简化):
@SuppressWarnings("serial")
abstract static class Completion extends AtomicInteger implements Runnable {
abstract CompletableFuture<?> tryFire(int mode);
}
4.1 设计要点
-
继承 AtomicInteger
利用compareAndSet来保证一个回调任务只会被执行一次(原子状态控制)。 -
实现 Runnable
方便直接在异步线程池中执行。 -
核心方法 tryFire(int mode)
mode通常表示执行模式(SYNC/ASYNC)。- 子类会实现该方法,在依赖任务完成后触发目标任务。
- 例如:
UniApply:处理 thenApply 回调BiApply:处理 thenCombine 回调OrApply:处理 applyToEither 回调
5. 三者协作机制
-
阻塞等待路径(WaitNode)
- 调用
get()/join()时,如果任务未完成,构造一个WaitNode入栈。 - 任务完成时,
postComplete()会遍历waiters栈,使用LockSupport.unpark(thread)唤醒等待线程。
- 调用
-
非阻塞回调路径(CompletionNode + Completion)
- 注册回调(thenApply、thenAccept 等)时,会构造对应的
Completion子类,并封装到CompletionNode入栈。 - 任务完成时,
postComplete()会遍历completions栈,调用每个Completion的tryFire()方法执行回调。
- 注册回调(thenApply、thenAccept 等)时,会构造对应的
-
Treiber 栈的使用
waiters和completions都是 Treiber 栈,入栈时使用 CAS,无需锁。- 遍历时是 LIFO 顺序,回调执行和唤醒线程是倒序的。
6. 总结
CompletableFuture 的高性能异步回调与阻塞等待机制,并不是依赖复杂的锁,而是通过 Treiber 栈 + CAS + 轻量节点结构 实现的。
- WaitNode:管理阻塞等待的线程,配合 ManagedBlocker 友好地支持 ForkJoinPool。
- CompletionNode:管理回调任务的链表节点。
- Completion:抽象回调逻辑的基类,提供统一的执行接口。
这种分离式的设计,使得 CompletableFuture 能够同时高效支持阻塞和非阻塞两种模式,满足各种并发场景的需求。

浙公网安备 33010602011771号