← [ BACK_TO_NOTES ]

Java CompletableFuture

CompletableFuture 如何组合异步任务、传递异常与配置执行器:避免阻塞式回调地狱。

#concept #growing #dev #java

[!info] related notes

Java CompletableFuture

这个概念为什么出现

Future.get() 会阻塞;多依赖组装易成回调泥潭。CompletableFuture 提供声明式异步组合:thenApply/thenCompose/exceptionally 等,把任务图表达清楚。

[!abstract] 一句话理解 CompletableFuture 是可手动完成、可组合的异步结果;需要异步调度时明确 Executor,并统一处理异常与超时;并非每个阶段都必须异步执行。

最小可运行示例

场景:并行查库存与价格,再汇总下单视图

import java.util.concurrent.*;

public class OrderViewAsync {
    public static void main(String[] args) throws Exception {
        ExecutorService pool = Executors.newFixedThreadPool(2);
        try {
            CompletableFuture<Integer> stock = CompletableFuture.supplyAsync(() -> 3, pool);
            CompletableFuture<Integer> price = CompletableFuture.supplyAsync(() -> 100, pool);
            CompletableFuture<String> view = stock.thenCombineAsync(price,
                    (s, p) -> "stock=" + s + ",price=" + p, pool);
            System.out.println(view.get(1, TimeUnit.SECONDS));
        } finally {
            pool.shutdown();
        }
    }
}

建议运行:

javac OrderViewAsync.java && java OrderViewAsync

期望输出:

stock=3,price=100

结合场景再看三个关注点

  1. supplyAsync 指定 pool,别默认打满 commonPool。
  2. thenCombine 表达汇合。
  3. get 设超时限制主线程本次等待,不会取消 stock/price/view 或底层操作。

核心概念与准确模型

1. 创建

  • supplyAsync / runAsync / completedFuture

2. 组合

  • thenApply 变换
  • thenCompose 扁平嵌套异步
  • thenCombine 两路汇合
  • allOf 等全部输入完成(包括异常完成),返回 Void 阶段,不直接收集值;它不是快速失败或自动取消工具。
  • anyOf 采用最先完成的结果或异常,不等于“第一个成功结果”,也不自动取消其他输入。\

3. 异常

  • exceptionally 可恢复异常结果;handle 变换成功或失败;whenComplete 主要观察结果,通常保留原结果(回调自身抛错仍可能影响返回阶段)。\
  • 异常完成时 get 通常抛 ExecutionException,join 通常抛 CompletionException;取消会抛 CancellationException。\

4. 超时

  • Java 9+ 的 orTimeout/completeOnTimeout 返回并可能完成当前 CompletableFuture:前者异常完成,后者给默认值;都不保证停止底层任务。\

边界情况与反直觉行为

  1. 非 Async 阶段可能由完成上游的线程执行,若上游已完成也可能在注册阶段的调用线程执行;Async 使用指定 Executor,未指定时通常用 commonPool。\
  2. 阻塞式调用占用 commonPool 可能拖慢其他共享任务;不能只靠 Async 后缀假设任务隔离。\
  3. CompletableFuture.cancel(true) 不会用中断控制底层计算,mayInterruptIfRunning 在此无效;需另行管理任务、请求或资源的取消。\

常见误区

[!warning] 常见误区:在 thenApply 里做重阻塞 IO 还不换池 IO 用专用 Executor 或虚拟线程策略。

工程实践

  1. 每条业务异步边界明确线程池。
  2. 统一包装异常为领域错误。
  3. 指标记录耗时与超时。
  4. 与响应式库边界分清,不混风格。

本节总结

  • CF=异步组合工具
  • Executor + 超时 + 异常
  • 汇合与扁平化是核心技能

自测题

  1. thenApply 与 thenCompose 差在哪?
  2. 为什么要避免默认 commonPool 跑阻塞任务?
参考答案
  1. apply 映射值;compose 用于返回另一个 CompletionStage 并扁平化。
  2. commonPool 被阻塞会拖垮其它并行任务。

延伸阅读与资料来源

资料类型支撑内容
CompletableFuture APIAPI组合方法
创建于 2026/7/15 更新于 2026/10/6
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本