如何在Java中使用 CompletableFuture 实现异步编程?

在 Java 8 引入了 CompletableFuture 类后,异步编程变得异常方便。它不但支持链式调用,还能处理结果、异常和组合任务。下面通过一个完整的示例来演示如何使用 CompletableFuture 做异步网络请求、并行计算以及错误回退。

1. 基础使用:完成一个异步任务

CompletableFuture <String> future =
    CompletableFuture.supplyAsync(() -> {
        // 模拟耗时操作,例如远程调用
        try { Thread.sleep(2000); } catch (InterruptedException e) { }
        return "Hello, CompletableFuture!";
    });

future.thenAccept(result -> System.out.println("获取结果:" + result));
  • supplyAsync 通过默认的 ForkJoinPool.commonPool() 线程池异步执行。
  • thenAccept 用于消费结果,返回 void

2. 结果转换与链式调用

CompletableFuture <String> future =
    CompletableFuture.supplyAsync(() -> "Java")
        .thenApply(name -> name + " 8")
        .thenApply(name -> name + " CompletableFuture")
        .thenApply(name -> name + " 学习");

future.thenAccept(System.out::println);

使用 thenApply 对结果做映射,形成链式转换,最终打印完整字符串。

3. 异常处理

CompletableFuture <Integer> future =
    CompletableFuture.supplyAsync(() -> {
        if (new Random().nextBoolean()) throw new RuntimeException("偶发错误");
        return 42;
    });

future.handle((result, ex) -> {
    if (ex != null) {
        System.out.println("异常:" + ex.getMessage());
        return -1;          // 退回默认值
    }
    return result;
}).thenAccept(System.out::println);
  • handle 无论成功还是异常都会执行,能够统一处理结果与错误。
  • 如果你只想捕获异常,可以使用 exceptionally

4. 并行任务组合

假设你需要同时请求用户信息、订单列表和推荐商品,三者之间没有先后关系,可并行执行后统一处理。

CompletableFuture <User> userFuture = CompletableFuture.supplyAsync(() -> fetchUser());
CompletableFuture<List<Order>> orderFuture = CompletableFuture.supplyAsync(() -> fetchOrders());
CompletableFuture<List<Product>> productFuture = CompletableFuture.supplyAsync(() -> fetchRecommendations());

CompletableFuture <Void> combinedFuture = CompletableFuture.allOf(userFuture, orderFuture, productFuture);

combinedFuture.thenRun(() -> {
    try {
        User user = userFuture.join();
        List <Order> orders = orderFuture.join();
        List <Product> products = productFuture.join();
        System.out.println("用户:" + user);
        System.out.println("订单:" + orders);
        System.out.println("推荐:" + products);
    } catch (CompletionException e) {
        System.err.println("组合任务中出现错误:" + e.getCause());
    }
});
  • allOf 等待所有任务完成。
  • join 用于获取结果,若出现异常会抛出 CompletionException

5. 受限并发:限制线程数

若你想用 CompletableFuture 但不想让所有任务同时跑到线程池(例如限制并发数为 5),可以配合 Executor

Executor limitedExecutor = Executors.newFixedThreadPool(5);

CompletableFuture <Void> all =
    CompletableFuture.allOf(
        tasks.stream()
             .map(task -> CompletableFuture.runAsync(task, limitedExecutor))
             .toArray(CompletableFuture[]::new)
    );

6. 结合 Spring Boot

在 Spring Boot 项目中,可以通过 @Async 注解和 AsyncTaskExecutor 配合 CompletableFuture 使用。

@Service
public class AsyncService {

    @Async("taskExecutor")
    public CompletableFuture <String> asyncMethod() {
        // 业务逻辑
        return CompletableFuture.completedFuture("async result");
    }
}

在配置类里:

@Bean(name = "taskExecutor")
public Executor taskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(10);
    executor.setMaxPoolSize(20);
    executor.setQueueCapacity(50);
    executor.setThreadNamePrefix("async-");
    executor.initialize();
    return executor;
}

然后在调用方:

@Autowired
AsyncService asyncService;

public void useAsync() {
    CompletableFuture <String> future = asyncService.asyncMethod();
    future.thenAccept(result -> System.out.println(result));
}

7. 小结

  • CompletableFuture 让异步编程像流式处理一样简洁。
  • supplyAsync/thenApply/thenAccept 形成基础链式调用。
  • handle/exceptionally 用于异常统一处理。
  • allOf/anyOf 用于任务组合与同步。
  • 可与自定义 Executor 配合控制并发度。
  • 在 Spring Boot 中可以结合 @Async 提升可维护性。

掌握以上几种用法后,你就能在 Java 项目中轻松实现高并发、低阻塞的异步处理方案。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注