CompletableFuture异步编排需选对方法、配好线程池、理清依赖:I/O任务显式指定线程池,串行用thenCompose防嵌套,allOf需手动join收结果,异常处理用handle/exceptionally/whenComplete分工。

CompletableFuture 实现异步编排与链式调用,核心在于用对方法、配好线程池、理清依赖关系。它不是简单把多个 supplyAsync 串起来,而是按任务性质(串行/并行/嵌套/聚合)选择对应组合算子,并避免默认线程池和类型误用带来的隐患。
选对创建方式:显式传入线程池,别碰 commonPool
默认 supplyAsync(Runnable) 或 supplyAsync(Supplier) 使用 ForkJoinPool.commonPool(),其并行度 = CPU 核数 − 1,且无界队列共享。I/O 类任务一多,线程全卡在阻塞上,后续任务排队,吞吐骤降,甚至触发 OOM。
- 用
supplyAsync(() -> doIoWork(), myIoPool)显式指定线程池 - I/O 密集型建议线程数设为
2 × CPU核数或根据压测调整;CPU 密集型可接近核数 - 推荐用
new ThreadPoolExecutor()构造,避免Executors.newCachedThreadPool()(无限扩容风险) - 应用关闭前调用
myIoPool.shutdown(),防止 JVM 挂起
串行依赖:thenCompose 处理“返回 CompletableFuture”的场景
上游返回的是一个 CompletableFuture<t></t>,下游还要基于它再发起异步操作?必须用 thenCompose,否则会套出 CompletableFuture<completablefuture>></completablefuture>,join() 或 get() 时直接 ClassCastException。
在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。
- ✅ 正确:
cf.thenCompose(s -> CompletableFuture.supplyAsync(() -> db.query(s))) - ❌ 错误:
cf.thenApply(s -> CompletableFuture.supplyAsync(() -> db.query(s)))→ 嵌套两层 CF - 上游返回普通值(如
String),下游只需同步转换(如转大写),用thenApply - 下游只消费不产出(如打日志),用
thenAccept;纯副作用(如发通知),用thenRun
并行聚合:allOf + join 手动收结果,别指望 allOf 返回数据
CompletableFuture.allOf(f1, f2, f3) 只表示“全部完成”,返回 CompletableFuture<void></void>,不带任何结果。想拿到三个异步任务的最终值,得自己收集。
立即学习“Java免费学习笔记(深入)”;
- 标准写法:
allOf(f1, f2, f3).thenApply(v -> Arrays.asList(f1.join(), f2.join(), f3.join())) -
join()不抛 checked exception,失败时包装为CompletionException,建议配合exceptionally()或handle()统一兜底 - 若任一失败就终止整个流程,可在每个子任务后加
exceptionally(e -> { throw new RuntimeException(e); }),或用handle((r, t) -> { if (t != null) throw new RuntimeException(t); return r; }) - 别对
allOf(...).get()直接调用——它没结果,只释放完成信号
异常与恢复:用对 handle / exceptionally / whenComplete
三者分工明确:
-
exceptionally(Function<throwable t>)</throwable>:仅当下游阶段抛异常时触发,返回替代值(如默认值),不处理正常完成 -
handle(BiFunction<t throwable r>)</t>:无论成功或失败都执行,适合统一记录、判空、做 fallback 转换 -
whenComplete(BiConsumer<t throwable>)</t>:只做副作用(如清理资源、打监控日志),不改变结果或异常流向

















