跳到正文
Elaine Blog
返回

Future 与 CompletableFuture 异步编排

并发编程

Future 表示一个尚未完成的结果,CompletableFuture 还能声明结果之间的依赖。异步编排必须同时设计执行器、截止时间、 异常语义和取消传播;只把同步调用包进 supplyAsync 不会自动获得可靠性。

Table of contents

Open Table of contents

运行组合示例

下载CompletableFuture 样例下载, 运行:

java -cp target/classes dev.elaine.concurrency.CompletableFutureSample

程序使用显式固定线程池,组合字符串转换,设置 1 秒超时,并在失败时返回降级结果。正常输出为 你好,并发学习者

thenApply 与 thenCompose

thenApply 转换普通结果;回调返回另一个异步阶段时使用 thenCompose 展平:

CompletableFuture<User> user = loadUser(id);
CompletableFuture<List<Order>> orders = user.thenCompose(value -> loadOrders(value.id()));

若使用 thenApply(value -> loadOrders(...)),类型会变成嵌套的 CompletableFuture<CompletableFuture<...>>。 独立任务可用 thenCombine 合并,但要考虑任一任务失败时另一个是否应该取消。

非 async 回调在哪个线程执行

Async 方法的回调可能由完成上一步的线程执行,也可能由触发完成的调用方执行。没有显式 Executor 的 Async 方法 通常使用 ForkJoinPool.commonPool()。因此不要在未知完成线程中执行长时间阻塞、访问线程上下文或持有框架锁。

关键业务使用独立、命名、有界的 Executor,并在每个异步边界显式传入。

超时不等于停止底层工作

orTimeout 会让 CompletableFuture 异常完成,但不保证正在执行的数据库或网络调用立即停止。底层客户端仍需连接、读取和 整体截止时间;取消也要传递到实际资源。

CompletableFuture.cancel 被视为异常完成。它不像 FutureTask 那样直接控制产生结果的计算,mayInterruptIfRunning 不应被当作可靠的强制中断协议。Java 25 的 CompletableFuture API 明确说明了这种取消语义。

异常处理不要吞根因

exceptionally 只适合明确的降级。需要记录成功或失败但保持结果时使用 whenComplete;需要把成功和失败都转换为新结果时 使用 handle。日志应保留根因和请求标识,但不能泄露 Token 或个人数据。

跨线程时 ThreadLocal 不会自动传播。显式传递不可变 Context,或使用框架提供且经过清理验证的上下文传播机制。

下一步

阅读ForkJoinPool、工作窃取与并行流,判断 CPU 密集任务何时值得 递归拆分。


分享这篇文章:

上一篇
ThreadPoolExecutor 参数、拒绝与动态调节
下一篇
ForkJoinPool、工作窃取与并行流