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. 自检
thenApply与thenCompose的区别?- 实测里
thenCombine为什么比串行快? allOf为什么不返回结果?怎么取?- 为什么 IO 密集任务要传自定义线程池?
- 异常不处理会怎样?怎么兜底?
8. 下一篇
S05-J04 · JVM 运行时数据区与垃圾回收基础
编排讲完,视角切到 JVM:对象在哪分配、什么时候被回收、栈帧长什么样。
本篇属于系列《S05 · Java 并发与 JVM》。旧文来源:A-1587;扩展点 E-S05-010。三条编排实测为 OpenJDK 21。
S05-J03 · 异步编排 CompletableFuture
https://www.clxhxhhr.top/posts/5249/ 评论
0 条
还没有评论,先写一条吧。