当Future遇上乐高:CompletableFuture是什么?
想象你在快餐店点餐:
- 传统Future:拿到取餐号后只能干等,不时问店员"好了没?"
- CompletableFuture:拿到智能取餐器,餐好自动震动提醒,还能顺便下单饮料和甜点
Java 8引入的CompletableFuture
就是这样一个智能的异步编程工具,它让多线程协作像搭积木一样简单流畅!
CompletableFuture的三大超能力
1. 异步任务链式调用(告别回调地狱)
CompletableFuture.supplyAsync(() -> "订单号:123") // 第一步生成订单
.thenApplyAsync(order -> order + " 状态:已支付") // 异步转换
.thenAcceptAsync(System.out::println); // 异步消费
2. 多任务组合(并行流水线)
CompletableFuture<String> queryUser = queryUserAsync(userId);
CompletableFuture<String> queryOrder = queryOrderAsync(orderId);
// 等两个查询都完成
queryUser.thenCombineAsync(queryOrder,
(user, order) -> "用户:" + user + " 订单:" + order
).thenAccept(System.out::println);
3. 异常处理(优雅降级)
CompletableFuture.supplyAsync(() -> {
if (Math.random() > 0.5) throw new RuntimeException("模拟异常");
return "正常结果";
})
.exceptionally(ex -> "降级结果") // 异常时返回默认值
.thenAccept(System.out::println);
4种创建方式对比
方式 | 示例代码 | 适用场景 |
---|---|---|
supplyAsync | supplyAsync(() -> "结果") | 有返回值的异步计算 |
runAsync | runAsync(() -> System.out.println("完成")) | 无返回值的异步任务 |
completedFuture | completedFuture("立即结果") | 已知结果的快速封装 |
自定义Completer | new CompletableFuture<>().complete("值") | 手动控制完成时机 |
5个真实业务场景
1. 电商订单处理流水线
// 并行查询用户信息、商品库存、优惠券
CompletableFuture<User> userFuture = getUserAsync(userId);
CompletableFuture<Stock> stockFuture = getStockAsync(itemId);
CompletableFuture<Coupon> couponFuture = getCouponAsync(userId);
// 全部完成后创建订单
CompletableFuture.allOf(userFuture, stockFuture, couponFuture)
.thenRun(() -> {
Order order = createOrder(
userFuture.join(),
stockFuture.join(),
couponFuture.join()
);
sendNotify(order);
});
2. 微服务聚合查询
// 同时调用三个微服务
CompletableFuture<Profile> profile = getProfileAsync(userId);
CompletableFuture<List<Order>> orders = getOrdersAsync(userId);
CompletableFuture<Recommend> recommends = getRecommendsAsync(userId);
// 合并结果返回
profile.thenCombine(orders, (p, o) -> new UserData(p, o))
.thenCombine(recommends, UserData::withRecommends)
.thenAccept(this::renderPage);
3. 超时熔断控制
// 设置3秒超时
CompletableFuture<String> dataFuture = fetchDataAsync()
.completeOnTimeout("默认数据", 3, TimeUnit.SECONDS);
// 或者超时抛出异常
fetchDataAsync().orTimeout(3, TimeUnit.SECONDS);
4. 异步任务编排
// 先登录,然后并行获取通知和消息,最后统一处理
loginAsync()
.thenCompose(user -> {
CompletableFuture<Notice> notice = getNoticeAsync(user);
CompletableFuture<Message> message = getMessageAsync(user);
return notice.thenCombine(message, (n, m) -> new UserView(user, n, m));
})
.thenAccept(this::updateUI);
5. 批量异步IO操作
List<CompletableFuture<String>> futures = urls.stream()
.map(url -> downloadAsync(url).exceptionally(ex -> "下载失败"))
.collect(Collectors.toList());
// 等所有下载完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenRun(() -> {
List<String> results = futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
processResults(results);
});
方法分类速查表
操作类型 | 关键方法 | 作用 |
---|---|---|
创建 | supplyAsync/runAsync/completedFuture | 创建异步任务 |
转换 | thenApply/thenApplyAsync | 对结果进行转换 |
消费 | thenAccept/thenRun | 消费结果无返回值 |
组合 | thenCompose/thenCombine/allOf/anyOf | 组合多个Future |
异常处理 | exceptionally/handle/whenComplete | 错误处理和恢复 |
控制 | completeOnTimeout/orTimeout | 超时控制 |
性能优化技巧
-
指定线程池:避免使用默认ForkJoinPool
ExecutorService pool = Executors.newFixedThreadPool(10); CompletableFuture.supplyAsync(() -> {...}, pool);
-
避免阻塞操作:特别是thenApply中使用同步IO
// 错误示范 .thenApply(id -> queryDB(id)) // 阻塞调用 // 正确做法 .thenCompose(id -> queryDBAsync(id)) // 返回新的Future
-
合理使用join:
// 在异步流程中尽量用thenAccept而不是join future.thenAccept(result -> {...}); // 优于 future.join()
-
资源清理:
// 使用whenComplete确保资源释放 openFileAsync().whenComplete((content, ex) -> { if (content != null) closeFile(content); });
常见陷阱规避
❌ 陷阱1:丢失异常堆栈
// 错误:异常信息不完整
future.exceptionally(ex -> {
System.out.println("出错:" + ex.getMessage());
return null;
});
// 正确:打印完整堆栈
future.whenComplete((res, ex) -> {
if (ex != null) ex.printStackTrace();
});
❌ 陷阱2:误用thenApply/thenCompose
// thenApply:用于同步转换
.thenApply(String::toUpperCase)
// thenCompose:用于异步转换(返回新的Future)
.thenCompose(id -> queryDBAsync(id))
❌ 陷阱3:忽略线程池配置
// 危险:所有任务共享默认ForkJoinPool
CompletableFuture[] futures = new CompletableFuture[1000];
Arrays.fill(futures, CompletableFuture.supplyAsync(blockingIOOperation));
// 正确:为IO密集型任务配置独立线程池
ExecutorService ioPool = Executors.newCachedThreadPool();
CompletableFuture.supplyAsync(blockingIOOperation, ioPool);
一句话总结
CompletableFuture就像编程世界的"异步乐高"——通过简单的链式调用组合出复杂的多线程工作流,让异步编程从"回调地狱"变成"声明式天堂"! 🧩⚡