949 字
约 3 分钟
7
S05-J03 · 异步编排 CompletableFuture

适用读者:写回调地狱、或不知道多个异步任务怎么合并的人。
前置:S05-B05。
实测环境:OpenJDK 21.0.12.1(2026-11-05)。
覆盖旧文:A-1587(CompletableFuture,163 点)。
覆盖扩展:E-S05-010(编排与异常处理)。
上一篇:S05-J02 · 并发容器:CHM、阻塞队列、COW
下一篇:S05-J04 · JVM 运行时数据区与 GC 基础。


1. 一句话结论

CompletableFuture 解决的是"编排":把 N 个异步任务按串行/并行/任一/全部组合起来,并把异常也变成可编排的一条数据流。


2. 实测:并行到底省多少

CompletableFuture<String> f = CompletableFuture.supplyAsync(() -> { sleep(300); return "A"; })
    .thenCombine(CompletableFuture.supplyAsync(() -> { sleep(300); return "B"; }), (x,y) -> x+y);

实测输出:

1. 并行合并: AB 耗时 361 ms(串行应 600ms 级)
2. 异常兜底: 兜底:boom
3. allOf 两个 200ms 任务 → 204 ms
编排 耗时 说明
串行两次 300ms ~600 ms 基准
thenCombine 并行 361 ms 两条 300ms 并行
allOf 两个 200ms 204 ms 全部完成才返回

3. 六个核心方法

方法 作用 备注
supplyAsync 异步有返回值 默认用 ForkJoinPool.commonPool()
thenApply 串行转换(同线程链) 前一个的结果作为输入
thenCombine 并行合并两个 实测 361ms
thenCompose 扁平化(返回另一个 CF) 避免 CF<CF<T>>
allOf / anyOf 全部/任一完成 allOf 无返回值,需自行 join 取结果
exceptionally / handle 异常兜底/统一处理 实测 兜底:boom

4. 三个必须知道的坑(E-S05-010)

坑 说明 对策
默认线程池是公共池 commonPool 大小 = 核数−1,IO 密集任务会互相拖累 传自定义 Executor
异常不显式处理会静默 没 join/get 时异常被吞 总加 exceptionally/whenComplete
allOf 不聚合结果 只保证都完成 完成后逐个 join 取值

判据:"这个任务会阻塞在 IO 上吗?" 会 → 必须传自定义线程池(否则拖垮公共池,影响所有使用 commonPool 的代码)。


5. 与普通 Future 的对比

能力 Future CompletableFuture
获取结果 get() 阻塞 回调/编排
组合多个 ❌ 手动 ✅ thenCombine/allOf
异常处理 ExecutionException 包裹 ✅ exceptionally/handle
链式 ❌ ✅

判据:只要涉及"多个异步任务协作",用 CompletableFuture;单个任务 Future 就够。


6. 五个误区

误区 真相
"thenApply 是异步的" 默认在完成它的那个线程上执行
"allOf 会返回结果集合" 不会,只有 CompletableFuture<Void>
"异常会自动抛出" 不 join/不处理会静默
"用公共池就行" IO 密集会把公共池占满
"任一完成用 anyOf 就能拿到结果" 拿到的是第一个完成的,需自行判空

7. 自检

  1. thenApply 与 thenCompose 的区别?
  2. 实测里 thenCombine 为什么比串行快?
  3. allOf 为什么不返回结果?怎么取?
  4. 为什么 IO 密集任务要传自定义线程池?
  5. 异常不处理会怎样?怎么兜底?

8. 下一篇

S05-J04 · JVM 运行时数据区与垃圾回收基础

编排讲完,视角切到 JVM:对象在哪分配、什么时候被回收、栈帧长什么样。


本篇属于系列《S05 · Java 并发与 JVM》。旧文来源:A-1587;扩展点 E-S05-010。三条编排实测为 OpenJDK 21。

S05-J03 · 异步编排 CompletableFuture
https://www.clxhxhhr.top/posts/5249/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。