Java异步流程控制核心是CompletableFuture,通过allOf实现并行任务等待、thenCombine合并两任务结果、thenCompose处理串行依赖,并支持exceptionally、handle、orTimeout等容错与超时机制。

Java 中的异步流程控制,核心是用 CompletableFuture 把多个独立或依赖的任务组织成清晰、可读、健壮的执行链。它不是简单“开几个线程”,而是通过组合语义表达“并行查、串行算、任一返回就用、出错自动兜底”这类真实业务逻辑。
并行发起多个独立任务(allOf)
适合同时加载用户信息、头像、积分等互不依赖的数据。
- 用
supplyAsync并行启动多个任务,推荐传入自定义线程池(避免挤占ForkJoinPool.commonPool()) - 用
CompletableFuture.allOf(f1, f2, f3)等待全部完成,它返回CompletableFuture<Void>,不携带结果 - 后续用
thenApply或直接调用各 future 的join()取值;注意join()会抛出 unchecked 异常,需配合exceptionally防止单点失败中断整体
示例:
CompletableFuture<String> user = supplyAsync(() -> api.getUser(id), pool);<br>CompletableFuture<String> avatar = supplyAsync(() -> api.getAvatar(id), pool);<br>CompletableFuture<Integer> points = supplyAsync(() -> api.getPoints(id), pool);<br><br>CompletableFuture<Void> all = CompletableFuture.allOf(user, avatar, points);<br>CompletableFuture<Profile> profile = all.thenApply(v -> <br> new Profile(user.join(), avatar.join(), points.join())<br>);
合并两个任务结果(thenCombine)
适合价格 + 折扣、用户 + 权限、订单 + 物流状态等两两配对计算场景。
立即学习“Java免费学习笔记(深入)”;
- 两个任务真正并行执行,不是先后触发
- lambda 参数顺序固定:第一个 future 结果在前,第二个在后
- 返回新
CompletableFuture,类型由 lambda 返回值决定,类型安全 - 任一失败则整个链失败,可用
exceptionally或handle统一兜底
示例:
CompletableFuture<BigDecimal> price = supplyAsync(() -> db.getPrice("A"), pool);<br>CompletableFuture<BigDecimal> discount = supplyAsync(() -> api.getDiscount("A"), pool);<br><br>CompletableFuture<BigDecimal> finalPrice = price<br> .thenCombine(discount, (p, d) -> p.subtract(d));
串行依赖调用(thenCompose)
适合“先查用户ID → 再用ID查订单 → 最后汇总”的链式异步流程。
- 和
thenApply的关键区别:后者返回普通值,前者必须返回另一个CompletableFuture - 避免“CompletableFuture<CompletableFuture<T>>”嵌套,自动展平(flat map 语义)
- 异常传播自然,上一步失败,后续不会执行
示例:
CompletableFuture<Long> userId = supplyAsync(() -> auth.getUserId(token));<br>CompletableFuture<Order> order = userId.thenCompose(id -> <br> supplyAsync(() -> orderService.getByUserId(id))<br>);
容错与超时控制
生产环境不能让一个慢请求拖垮整个流程。
-
exceptionally:只处理异常,返回默认值(如空字符串、-1、空列表),类型需匹配 -
handle:统一处理成功结果和异常,适合记录日志+返回兜底值 -
orTimeout:设置超时时间,超时后抛出TimeoutException,可接exceptionally转为友好结果 - 避免在 lambda 中写阻塞操作(如
Thread.sleep、同步 IO),否则会卡住线程池
不复杂但容易忽略


















