CompletableFuture 异步编程工具类

1. 优势

  • ✅ 非阻塞的异步编程

  • ✅ 声明式链式调用

  • ✅ 强大的组合能力

  • ✅ 丰富的异常处理

  • ✅ 手动设置结果的能力

2. 入门

1. 先学两个入口

只有这两个最重要:

  • runAsync(...)
    没有返回值,适合"异步做一件事"
  • supplyAsync(...)
    有返回值,适合"异步算一个结果"
java 复制代码
CompletableFuture<Void> f1 = CompletableFuture.runAsync(() -> {
    System.out.println("异步执行任务");
}, executor);

CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> {
    return "查询结果";
}, executor);

2. 结果回来后怎么接

最常用 3 个:

  • thenApply
    有入参,有返回值。适合"转换结果"
  • thenAccept
    有入参,无返回值。适合"消费结果"
  • thenRun
    没入参,没返回值。适合"只想接着执行"
java 复制代码
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "abc", executor);

CompletableFuture<Integer> lenFuture = future.thenApply(s -> s.length());

CompletableFuture<Void> saveFuture = future.thenAccept(s -> {
    System.out.println("保存结果: " + s);
});

CompletableFuture<Void> logFuture = future.thenRun(() -> {
    System.out.println("任务结束");
});

3. 异常怎么处理

最常用 2 个:

  • exceptionally
    出错时兜底
  • handle
    不管成功失败都能处理
java 复制代码
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    if (true) throw new RuntimeException("出错了");
    return "ok";
}, executor).exceptionally(ex -> {
    System.out.println("捕获异常: " + ex.getMessage());
    return "默认值";
});
java 复制代码
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    if (true) throw new RuntimeException("出错了");
    return "ok";
}, executor).exceptionally(ex -> {
    System.out.println("捕获异常: " + ex.getMessage());
    return "默认值";
});

4. 多个异步任务一起跑

这也是 CompletableFuture 很强的地方。

allOf(...):等全部完成

anyOf(...):谁先完成用谁

java 复制代码
CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> 1, executor);
CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> 2, executor);

CompletableFuture<Void> all = CompletableFuture.allOf(f1, f2);

all.join(); // 等全部完成

int sum = f1.join() + f2.join();
System.out.println(sum);

5. join() 和 get() 的区别

两者都是"等结果"。

  • get()
    抛检查异常,写法啰嗦
  • join()
    抛运行时异常,写法更简洁

一般项目里更常见 join()。

java 复制代码
String result = future.join();

6. thenApply 和 thenCompose 的区别

这个新手最容易混。

如果你的下一步返回的是"普通值",用 thenApply。

如果你的下一步返回的是"另一个 CompletableFuture",用 thenCompose。

java 复制代码
CompletableFuture<String> f =
    CompletableFuture.supplyAsync(() -> "userId", executor)
        .thenCompose(userId -> CompletableFuture.supplyAsync(() -> "order of " + userId, executor));

7. 线程池很重要

如果你不传线程池,默认会走公共线程池 ForkJoinPool.commonPool()。

java 复制代码
CompletableFuture.supplyAsync(() -> query(), modelApiThreadPool);