Skip to content
进阶

一句话答案

CompletableFuture 支持异步编排和组合:supplyAsync→thenApply→exceptionally,比 Future 强大且不阻塞。

核心要点

CompletableFuture vs Future:

Future 的局限:
  ① get() 阻塞 → 失去异步意义
  ② 无法组合多个异步任务
  ③ 无法注册回调(任务完成后自动执行下一步)

CompletableFuture 解决了所有问题 → 非阻塞链式异步编排

核心用法:

java
// 1. 创建异步任务
CompletableFuture<String> future = CompletableFuture.supplyAsync(
    () -> queryUserFromDB(userId),   // 异步执行,返回结果
    customExecutor                    // 可指定线程池(推荐,避免用公共 ForkJoinPool)
);

// 2. 链式转换(thenApply = map)
CompletableFuture<UserDTO> dtoFuture = future
    .thenApply(user -> convertToDTO(user));   // 上一步完成后,同步转换

// 3. 链式消费(thenAccept = forEach)
future.thenAccept(user -> log.info("查到用户: {}", user));

// 4. 链式执行(thenRun,不关心上一步结果)
future.thenRun(() -> log.info("任务完成"));

// 5. 异常处理
future.exceptionally(ex -> {
    log.error("查询失败", ex);
    return defaultUser;   // 返回兜底值
});

// 6. handle(同时处理正常结果和异常)
future.handle((result, ex) -> {
    if (ex != null) return defaultUser;
    return result;
});

多任务组合:

java
// 1. 两个任务都完成后合并结果(thenCombine)
CompletableFuture<String> userFuture = supplyAsync(() -> queryUser(id));
CompletableFuture<String> orderFuture = supplyAsync(() -> queryOrder(id));

CompletableFuture<String> combined = userFuture.thenCombine(
    orderFuture,
    (user, order) -> user + " 的订单: " + order  // 两个都完成后合并
);

// 2. 等待所有任务完成(allOf)
CompletableFuture<Void> all = CompletableFuture.allOf(
    queryUser(), queryOrder(), queryAddress()
);
all.thenRun(() -> log.info("三个查询全部完成"));

// 3. 任意一个完成即返回(anyOf)
CompletableFuture<Object> fastest = CompletableFuture.anyOf(
    queryFromMirror1(), queryFromMirror2(), queryFromMirror3()
);

生产实践 — 并行查询多个服务:

java
public UserDetailVO getUserDetail(Long userId) {
    CompletableFuture<User> userFuture = supplyAsync(() -> userService.getById(userId), executor);
    CompletableFuture<List<Order>> orderFuture = supplyAsync(() -> orderService.listByUserId(userId), executor);
    CompletableFuture<Address> addrFuture = supplyAsync(() -> addressService.getByUserId(userId), executor);

    CompletableFuture.allOf(userFuture, orderFuture, addrFuture).join();

    return new UserDetailVO(userFuture.join(), orderFuture.join(), addrFuture.join());
}
// 三个查询并行执行,总耗时 = max(三个查询) 而不是三个之和

注意事项:

① 不要用默认的 ForkJoinPool.commonPool(),应指定业务线程池
② supplyAsync 中的异常不会自动抛出,必须用 exceptionally/handle 处理
③ join() 和 get() 的区别:join() 抛 CompletionException(unchecked),get() 抛 checked exception
④ thenApply vs thenApplyAsync:不带 Async 在上一步的线程中执行,带 Async 提交到线程池
追问与易错

追问方向:

  • thenApply 和 thenCompose 的区别?
  • 异常处理用 exceptionally 还是 handle?
  • 不指定线程池有什么问题?

易错点:

  • ❌ CompletableFuture 自动处理异常——未捕获的会被静默吞掉
  • ❌ 链太长不拆分——影响可读性

💡 记忆锚点

CompletableFuture 是异步任务的流水线:supplyAsync 启动第一道工序,thenApply 接力下一道,exceptionally 兜底次品处理。多条流水线可以用 allOf 等全部完工,也可以用 anyOf 谁先做完用谁的——告别 Future.get() 的"傻等"模式。