Z
ZHANK
编程在线教程Java 教程CompletableFuture 异步编程
多线程

CompletableFuture 异步编程

掌握异步编排、thenApply、thenCombine、异常处理

CompletableFuture 异步编程

前面学了用线程池提交任务,但如果多个任务之间有依赖关系(A 完成后 B 才能开始,C 需要 A 和 B 的结果),用 Future.get() 阻塞等待会让代码又臭又长。CompletableFuture链式声明解决这个问题——你只管描述"先做什么、再做什么",不用手动等。

学完本章你将: 创建异步任务、链式编排、组合任务、异常处理。


为什么需要 CompletableFuture

java
// ❌ 传统 Future.get() —— 阻塞等待,链式困难
Future<User> userFuture = pool.submit(() -> fetchUser(1));
User user = userFuture.get(); // 阻塞!当前线程卡住
Future<List<Order>> orderFuture = pool.submit(() -> fetchOrders(user.getId()));
List<Order> orders = orderFuture.get(); // 又阻塞!

// ✅ CompletableFuture —— 声明式链式
CompletableFuture.supplyAsync(() -> fetchUser(1))
    .thenApply(user -> fetchOrders(user.getId()))  // 自动等 user 完成再执行
    .thenAccept(orders -> System.out.println(orders)); // 自动等 orders 完成

创建与获取

java
// 无返回值
CompletableFuture<Void> f1 = CompletableFuture.runAsync(() -> {
    System.out.println("异步执行");
});

// 有返回值 —— 用 supplyAsync
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> {
    return "返回结果";
});

// 阻塞等待(测试时用)
String result = f2.get();  // 阻塞直到完成
String result2 = f2.join(); // 效果一样,但不抛受检异常

链式处理 —— 流水线

每个 then* 方法都返回新的 CompletableFuture,让你像搭积木一样串联操作:

java
CompletableFuture.supplyAsync(() -> fetchUser(1))       // 异步获取用户
    .thenApply(user -> user.getName())                   // 拿到用户 → 取名字
    .thenApply(String::toUpperCase)                      // 转大写
    .thenAccept(name -> System.out.println("结果:" + name)) // 最终消费
    .thenRun(() -> System.out.println("流程结束"));       // 最后执行
方法做什么有无入参
`thenApply`转换结果✅ 拿上一步结果
`thenAccept`消费结果
`thenRun`最后收尾

组合多个任务 —— 等这个也等那个

java
CompletableFuture<String> hello = supplyAsync(() -> "Hello");
CompletableFuture<String> world = supplyAsync(() -> "World");

// thenCombine:两个都完成,合并结果
hello.thenCombine(world, (h, w) -> h + " " + w)
     .thenAccept(System.out::println); // "Hello World"

// allOf:等所有完成(不合并结果)
CompletableFuture.allOf(hello, world).join();

// anyOf:任意一个完成就往下走
CompletableFuture.anyOf(hello, world).thenAccept(System.out::println);

异常处理

java
CompletableFuture.supplyAsync(() -> {
    if (Math.random() > 0.5) throw new RuntimeException("炸了");
    return "成功";
})
.exceptionally(ex -> "默认值")  // 异常时兜底
.thenAccept(System.out::println); // 总能拿到值