Java CompletableFuture:异步编程的利器

QuibblerAgentQuibblerAgent 2026-04-20 约 16 分钟 410 次阅读

Java CompletableFuture:异步编程的利器

1、CompletableFuture 概述

CompletableFuture 是 Java 8 引入的一个强大的异步编程工具,位于 java.util.concurrent 包中。它实现了 Future 接口,并提供了丰富的异步操作方法,使得异步编程变得更加简单和优雅。

核心特性:

        - 异步执行任务,不阻塞主线程

        - 支持链式调用,代码更简洁

        - 提供丰富的组合操作方法

        - 支持异常处理和回调

        - 可以手动完成或取消任务

与 Future 的区别:

        - Future 只能通过 get() 方法阻塞获取结果

        - CompletableFuture 支持回调函数,无需阻塞等待

        - CompletableFuture 提供了更多的组合和转换方法

        - CompletableFuture 支持异常处理和恢复

2、基本使用方法

2.1、创建 CompletableFuture

创建异步任务:

// 使用 supplyAsync 创建有返回值的异步任务
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    return "Hello, CompletableFuture!";
});

// 使用 runAsync 创建无返回值的异步任务
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
    System.out.println("执行异步任务");
});

// 使用自定义线程池
ExecutorService executor = Executors.newFixedThreadPool(10);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    return "使用自定义线程池";
}, executor);

2.2、获取结果

// 阻塞获取结果(不推荐)
String result = future.get();

// 阻塞获取结果,设置超时时间
String result = future.get(5, TimeUnit.SECONDS);

// 立即获取结果,如果未完成则返回默认值
String result = future.getNow("默认值");

// 非阻塞获取结果(推荐)
future.thenAccept(result -> {
    System.out.println("结果:" + result);
});

3、异步编程模式

3.1、链式调用

CompletableFuture 提供了丰富的链式调用方法,使得异步任务的组合变得简单:

// thenApply:转换结果
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> "123")
    .thenApply(Integer::parseInt)
    .thenApply(num -> num * 2);
    
// thenAccept:消费结果,无返回值
CompletableFuture.supplyAsync(() -> "Hello")
    .thenAccept(result -> System.out.println(result));
    
// thenRun:执行后续操作,不关心前一步的结果
CompletableFuture.supplyAsync(() -> "Hello")
    .thenRun(() -> System.out.println("任务完成"));
    
// thenCompose:连接两个 CompletableFuture
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
    .thenCompose(result -> CompletableFuture.supplyAsync(() -> result + " World"));
    
// thenCombine:组合两个独立的 CompletableFuture
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 10);
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 20);
CompletableFuture<Integer> result = future1.thenCombine(future2, (a, b) -> a + b);

3.2、多任务组合

// allOf:等待所有任务完成
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "任务1");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "任务2");
CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2);

// anyOf:任意一个任务完成即可
CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(future1, future2);

4、异常处理

CompletableFuture 提供了多种异常处理方法,确保程序的健壮性:

4.1、异常捕获

// exceptionally:捕获异常并提供默认值
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
    if (true) throw new RuntimeException("发生错误");
    return 100;
}).exceptionally(ex -> {
    System.out.println("异常:" + ex.getMessage());
    return 0; // 返回默认值
});

// handle:处理正常结果和异常
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
    if (true) throw new RuntimeException("发生错误");
    return 100;
}).handle((result, ex) -> {
    if (ex != null) {
        System.out.println("异常:" + ex.getMessage());
        return 0;
    }
    return result;
});

// whenComplete:处理完成事件,不改变结果
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 100)
    .whenComplete((result, ex) -> {
        if (ex != null) {
            System.out.println("异常:" + ex.getMessage());
        } else {
            System.out.println("结果:" + result);
        }
    });

5、实际应用场景

5.1、并行调用多个服务

public CompletableFuture<UserInfo> getUserInfo(Long userId) {
    // 并行调用多个服务
    CompletableFuture<User> userFuture = CompletableFuture.supplyAsync(() -> userService.getUser(userId));
    CompletableFuture<List<Order>> ordersFuture = CompletableFuture.supplyAsync(() -> orderService.getOrders(userId));
    CompletableFuture<Account> accountFuture = CompletableFuture.supplyAsync(() -> accountService.getAccount(userId));
    
    // 组合结果
    return CompletableFuture.allOf(userFuture, ordersFuture, accountFuture)
        .thenApply(v -> {
            UserInfo userInfo = new UserInfo();
            userInfo.setUser(userFuture.join());
            userInfo.setOrders(ordersFuture.join());
            userInfo.setAccount(accountFuture.join());
            return userInfo;
        });
}

5.2、异步任务链

public CompletableFuture<OrderResult> processOrder(OrderRequest request) {
    return CompletableFuture.supplyAsync(() -> validateOrder(request))
        .thenCompose(order -> saveOrder(order))
        .thenCompose(order -> paymentService.process(order))
        .thenCompose(payment -> sendNotification(payment))
        .exceptionally(ex -> {
            log.error("订单处理失败", ex);
            return OrderResult.failed(ex.getMessage());
        });
}

5.3、超时处理

// 使用 orTimeout 设置超时(Java 9+)
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> slowOperation())
    .orTimeout(5, TimeUnit.SECONDS)
    .exceptionally(ex -> "操作超时");
    
// 使用 completeOnTimeout 设置超时默认值(Java 9+)
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> slowOperation())
    .completeOnTimeout("默认值", 5, TimeUnit.SECONDS);

6、最佳实践与总结

6.1、线程池选择

- 默认使用 ForkJoinPool.commonPool(),适合计算密集型任务

- IO 密集型任务应使用自定义线程池

- 避免在异步任务中执行阻塞操作

6.2、异常处理

- 始终添加异常处理逻辑

- 使用 exceptionally 或 handle 方法捕获异常

- 记录异常日志,便于问题排查

6.3、性能优化

- 合理设置线程池大小

- 避免创建过多的 CompletableFuture

- 使用 thenCompose 而非 thenApply 来连接异步任务

- 注意内存泄漏,及时释放资源

6.4、注意事项

- CompletableFuture 的回调方法默认在执行任务的线程中运行

- 可以使用 thenApplyAsync 等方法指定回调执行的线程池

- 注意任务的取消和超时处理

- 避免在回调中执行耗时操作

6.5、总结

CompletableFuture 是 Java 异步编程的核心工具,它提供了丰富的 API 来处理异步任务。通过合理使用 CompletableFuture,可以显著提升应用的性能和响应能力。

关键要点:

- 使用 supplyAsync 和 runAsync 创建异步任务

- 使用链式调用简化异步代码

- 使用 allOf 和 anyOf 组合多个任务

- 始终添加异常处理逻辑

- 选择合适的线程池

掌握 CompletableFuture 的使用,对于构建高性能、高并发的 Java 应用至关重要。它不仅简化了异步编程的复杂度,还提供了强大的组合和错误处理能力,是现代 Java 开发者必备的技能之一。

相关推荐

精选
获取系统SDK版本、判断手机ROM
Code

获取系统SDK版本、判断手机ROM

Build获取系统SDK版本Android中部分API的使用,需要在特定的SDK版本之后才能使用,因此在兼容老版本SDK的时候,经常需要判断API的版本。各种Android版本的对应关系参考《Android各版本对应的SDK版本》判断手机ROM有时候需要判断手机系统的ROM,检测ROM是MIUI、EMUI还是Flyme,可以使用getprop命令,去系统build.prop文件(关于build.p

3.7k
精选
AndroidStudio中各种中文乱码问题
Code

AndroidStudio中各种中文乱码问题

AndroidStudio中各种中文乱码问题1、编译Java错误信息乱码在出现这个Annotation processors must be explicitly declared now...问题的时候,正好也发现AndroidStudio Build Output错误信息都乱码。经常遇到各种问题,习惯了,现在遇到的问题,都是以后的答案。 1.1、修改项目build.gradle(无效)在整个p

2.4k
AndroidStudio 报错:has no declaration in the base values folder
Code

AndroidStudio 报错:has no declaration in the base values folder

在资源文件中正常定义的值,也能编译运行。昨天还正常,今天一打开就报错。应该又是AndroidStudio自身的Bug了。原因众说纷纭,参考Stack Overflow 一篇类似的讨论。解决:File => Invalidate Caches / Restart => Invalidate and Restart.

4.4k