completablefuture异步编排原理基于状态机驱动、completionstage链式契约和内部completion链表结构,通过“完成即触发”的被动通知机制实现非阻塞调度,而非轮询或定时器。

要真正看懂 CompletableFuture 的异步编排原理,不能只盯着它暴露的 API,得回到 JDK 源码里抓住三个关键锚点:状态机驱动、CompletionStage 的链式契约、内部 Completion 链表结构。它不是靠轮询或定时器,而是靠“完成即触发”的被动通知机制。
状态流转是整个编排的引擎
CompletableFuture 内部用一个 volatile 的 result 字段承载三种状态:
- 未完成:字段为
null,同时存在一个等待队列(waiters) - 正常完成:字段指向计算结果(可能为
null) - 异常完成:字段指向包装了异常的
AltResult实例
所有 complete、completeExceptionally、obtrudeValue 等方法,本质都是原子更新这个字段,并在成功时触发后续动作——不是“主动拉取”,而是“完成即推”。
CompletionStage 定义了链式行为契约
CompletableFuture 实现了 CompletionStage 接口,而该接口中每个 then* 方法都约定:返回一个新的 CompletionStage 实例,且新实例与原实例构成依赖关系。源码里这类方法(如 thenApply)实际做三件事:
- 创建一个新的 CompletableFuture 对象(代表下一阶段)
- 把当前 stage 的 result 或 exception 封装成一个
UniApply节点,挂到新 stage 的dep字段上 - 如果当前 stage 已完成,立刻尝试执行该节点;否则等将来完成时再触发
这种“节点挂载 + 延迟执行”机制,让整个链天然支持异步非阻塞,也避免了回调地狱。
OpenJDK 24 Windows x64 官方参考实现(24+36),适合 Windows 环境进行 Java 开发、编译、运行和版本兼容性验证。
内部 Completion 链表实现真正的依赖调度
每个 CompletableFuture 对象内部维护一个 static final class UniApply<t> extends UniCompletion<t></t></t> 类型的节点,它继承自 Completion,并持有:
- 上游 stage 引用(
src) - 下游 stage 引用(
dst) - 待执行的函数(
fn) - 执行所需的线程上下文(
executor)
当 src 完成时,会遍历其所有挂载的 Completion 节点,对每个节点调用 tryFire——这个方法判断是否能立即执行(比如 executor 可用),若能则提交任务;若不能(比如线程池满),就尝试将节点压入 dst 的 waiters 队列,等 dst 后续被唤醒。
Async 方法背后是线程切换控制权
thenApplyAsync 和 thenApply 的区别不在功能,而在执行线程归属:
-
thenApply:复用前一阶段完成时所在的线程(可能是 ForkJoinWorkerThread,也可能是主线程),适合轻量计算 -
thenApplyAsync:强制交由指定 executor(默认ForkJoinPool.commonPool())执行,用于隔离 IO 或重负载操作
源码中对应逻辑体现在 UniApply.tryFire 的分支判断:是否传入 executor,决定了是直接 run() 还是 submit()。










