CompletableFuture异步编排本质是定义控制流关系而非写顺序代码:allOf用于并行等待、thenCompose处理异步串行依赖、thenCombine/thenAcceptBoth实现双任务结果合并、handle/exceptionally支持条件分支与错误兜底。

Java 中用 CompletableFuture 做异步编排,本质不是写“顺序代码”,而是定义“执行控制流之间的关系”。多路控制流(比如并行、串行、条件分支、聚合等待)靠组合方法实现,不靠 if/for/while 等传统结构。关键在于选对方法、配好线程池、理清数据流向。
并行执行 + 全部等待(allOf)
适用于多个独立任务同时发起、必须等全部完成才继续的场景,比如加载用户头像、简介、积分三类数据:
- 用 CompletableFuture.allOf(f1, f2, f3) 汇聚多个 CompletableFuture
,它本身不携带结果,只表示“全部完成”这个事件 - 后续逻辑用 thenRun 或 thenApply(需手动 .join() 取各子任务结果)
- 注意:allOf 不会传播子任务异常;任一失败,allOf 仍算“完成”,但调用 join() 会抛出 CompletionException
串行依赖 + 异步传递(thenCompose)
适用于后一步必须等前一步结果、且该步骤本身也是异步的——这是最易出错也最关键的控制流。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 用 thenCompose,不是 thenApply:前者接收返回 CompletableFuture 的函数,并自动展平;后者只做同步转换,会导致 CompletableFuture
> 套娃 - 每一步都应显式指定线程池(如 ioPool),避免默认 commonPool 被阻塞型操作拖垮
- 示例:fetchUserId().thenCompose(id → fetchProfile(id), ioPool).thenCompose(profile → enrich(profile), ioPool)
并行执行 + 结果合并(thenCombine / thenAcceptBoth)
适用于两个(或有限个)独立异步任务完成后,用它们的结果一起计算新值。
立即学习“Java免费学习笔记(深入)”;
- thenCombine:接收两个 CompletableFuture 和一个 BiFunction,返回带新结果的 CompletableFuture
-
thenAcceptBoth:只消费两个结果,不产生新结果(返回 CompletableFuture
) - 二者都不阻塞,也不要求两个任务启动时间一致;谁先完成谁先等另一个,整体以慢者为准
条件分支与错误中断(handle / exceptionally)
CompletableFuture 没有原生 if-else,但可通过 handle 实现运行时分支决策,或用 exceptionally 做异常兜底。
-
handle(BiFunction
) :无论成功或失败都会触发,可检查异常并返回默认值、重抛、或转为其他 CompletableFuture -
exceptionally(Function
) :仅在异常时触发,适合返回降级值;但它不中断链——后续 thenCompose 仍会执行,需配合 null 判断或主动 throw - 想真正中断流水线,可在 handle 中返回 null,再在下一级用 thenCompose(r → r == null ? CompletableFuture.failedFuture(...) : ...)

















