CompletableFuture 的本质是将等待和执行分离,让多个任务可以并行执行,最后统一汇总结果。这种设计让异步编程从复杂的手动管理变成了简单的链式组合。
一、实战场景(Practical Scenarios):从简单到复杂
通过实际场景理解 CompletableFuture 的应用,从多数据源并行查询到异步任务链式处理,每个场景都展示了 CompletableFuture 解决实际问题的能力。
1.1 多数据源并行查询:总耗时约等于最慢的那个(性能提升可达数倍)
并行查询多个数据源,总耗时约等于最慢的那个查询,而不是所有查询的累加。这是 CompletableFuture 最典型的应用场景。
public UserProfile getUserProfile(Long userId) {
// 并行查询三个数据源
CompletableFuture<UserInfo> userFuture = CompletableFuture.supplyAsync(() -> userService.getUserInfo(userId)); // 耗时 200ms
CompletableFuture<List<Order>> ordersFuture = CompletableFuture.supplyAsync(() -> orderService.getUserOrders(userId)); // 耗时 300ms
CompletableFuture<PointsInfo> pointsFuture = CompletableFuture.supplyAsync(() -> pointsService.getUserPoints(userId)); // 耗时 150ms
// 等待所有查询完成并组合结果
return CompletableFuture.allOf(userFuture, ordersFuture, pointsFuture).thenApply(v -> {
UserProfile profile = new UserProfile();
profile.setUserInfo(userFuture.join());
profile.setOrders(ordersFuture.join());
profile.setPoints(pointsFuture.join());
return profile;
}).join(); // 总耗时:300ms(最慢的那个),而不是 650ms(串行)
}
性能提升:
- 串行执行:总耗时 = 200ms + 300ms + 150ms = 650ms
- 并行执行:总耗时 = max(200ms, 300ms, 150ms) = 300ms
- 性能提升:约 2.2 倍
适用场景:
- 需要从多个数据源查询数据
- 各个查询之间没有依赖关系
- 需要组合多个查询结果
1.2 异步任务链式处理:前一个任务的输出作为后一个任务的输入(形成清晰的处理链)
将多个异步任务串联,前一个任务的输出作为后一个任务的输入,形成清晰的处理链。这是理解 thenCompose 使用场景的关键示例。
public void {
CompletableFuture.supplyAsync(() -> {
userService.validateUser(userId);
}).thenCompose(isValid -> {
(!isValid) {
();
}
CompletableFuture.supplyAsync(() -> dataService.getUserData(userId));
}).thenAccept(data -> {
notificationService.sendNotification(userId, );
}).exceptionally(ex -> {
log.error(, ex);
notificationService.sendNotification(userId, + ex.getMessage());
;
});
}

