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

在Java 8及以后的版本中,CompletableFuture提供了一种非常灵活的方式来处理异步任务。相比传统的回调和Future接口,CompletableFuture可以链式组合、异常处理、并发并行执行等,代码更简洁易读。下面以一个典型的异步请求数据并进行处理的例子来说明使用方法。

1. 基础使用

CompletableFuture <String> future = CompletableFuture.supplyAsync(() -> {
    // 模拟耗时操作(例如网络请求)
    try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
    return "Hello, CompletableFuture!";
});

future.thenAccept(result -> System.out.println("得到结果:" + result));
  • supplyAsync:在默认的ForkJoinPool中执行耗时任务,返回结果供后续处理。
  • thenAccept:在完成后接收结果进行消费。

2. 组合异步任务

假设我们需要先请求用户信息,然后再根据用户ID去查询订单。两者可以串行或并行组合:

CompletableFuture <User> userFuture = CompletableFuture.supplyAsync(() -> fetchUser());
CompletableFuture<List<Order>> ordersFuture = userFuture.thenCompose(user ->
    CompletableFuture.supplyAsync(() -> fetchOrders(user.getId())));

ordersFuture.thenAccept(orders -> System.out.println("订单数量:" + orders.size()));
  • thenCompose:将前一个任务的结果作为输入,再返回一个新的CompletableFuture,实现任务链。
  • thenApply:如果不需要再返回Future,只做一次转换,可用thenApply

3. 并行处理

如果你有多个独立任务,可以使用allOfanyOf实现并行:

CompletableFuture <Void> all = CompletableFuture.allOf(
    CompletableFuture.runAsync(() -> taskA()),
    CompletableFuture.runAsync(() -> taskB()),
    CompletableFuture.runAsync(() -> taskC())
);

all.thenRun(() -> System.out.println("所有任务完成"));
  • runAsync:返回void类型的CompletableFuture
  • allOf:等待所有Future完成。
  • anyOf:等待任意一个Future完成。

4. 异常处理

在链式调用中,一旦出现异常,后续处理将被跳过。可以使用exceptionallyhandle来捕获:

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

future
    .exceptionally(ex -> {
        System.err.println("异常:" + ex.getMessage());
        return "默认值";
    })
    .thenAccept(result -> System.out.println("最终结果:" + result));

5. 实践案例:异步查询用户与订单

class User { String id; String name; /* getters */ }
class Order { String id; String userId; /* getters */ }

CompletableFuture <User> fetchUserAsync(String userId) {
    return CompletableFuture.supplyAsync(() -> {
        // 模拟查询
        try { Thread.sleep(200); } catch (InterruptedException ignored) {}
        return new User(userId, "Alice");
    });
}

CompletableFuture<List<Order>> fetchOrdersAsync(String userId) {
    return CompletableFuture.supplyAsync(() -> {
        // 模拟查询
        try { Thread.sleep(300); } catch (InterruptedException ignored) {}
        return List.of(new Order("O1", userId), new Order("O2", userId));
    });
}

void demo(String userId) {
    fetchUserAsync(userId)
        .thenCompose(user -> fetchOrdersAsync(user.getId()))
        .thenAccept(orders -> System.out.println("订单数量:" + orders.size()))
        .exceptionally(ex -> {
            System.err.println("查询失败:" + ex);
            return null;
        });
}

调用 demo("U123"),即可看到异步流程完成后打印订单数量。

6. 小结

  • CompletableFuture使异步编程变得像同步代码一样易读易写。
  • 通过 supplyAsync, runAsync, thenApply, thenCompose, thenAccept, exceptionally 等方法,能够实现复杂的任务流。
  • 结合 allOfanyOf 可轻松处理并行任务。
  • 充分利用异常处理机制,保持代码健壮。

使用好 CompletableFuture,可以显著提升 Java 后台服务的并发性能与代码可维护性。祝你编码愉快!

评论

发表回复

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