CompletableFuture 异步编程

55 阅读2分钟

CompletableFuture 是 Java8 引入的一个强大的工具,用于异步编程。它提供了一个灵活的方式来处理异步任务,并且可以轻松的将多个异步操作组合在一起。

基本概念

  • 异步计算:可以用于表示一个异步计算的结果。当计算完成时,可以设置结果或异常
  • 非阻塞:可以启动一个长时间运行的任务,并在任务完成时得到通知,而无需阻塞当前线程
  • 组合:支持将多个CompletableFuture 组合在一起,行程复杂的异步操作链

创建

supplyAsync 带有返回值

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // 执行业务逻辑
    return "Hello, World!";
});

runAsync 无返回值

CompletableFuture.runAsync(() -> {
    // 执行业务逻辑
});

结果

阻塞等待结果

get 阻塞等待

String result = future.get();

非阻塞等待

  • thenApply 处理并返回结果
  • **thenAccept ** 消费结果但不返回
  • **thenRun ** 完成时运行代码
future.thenApply(result -> {
    // 处理并返回结果
    return result.toUpperCase();
})
.thenAccept(result - > {
    // 执行业务逻辑操作,消费结果但不返回
})
.thenRun(()-> {
    // 当任务执行完成时
})

异常处理

exceptionally 当出现异常时会执行到此方法内

future
.exceptionally(ex -> {
    // 当出现异常时会执行到此方法内
    System.out.println("Exception: " + ex.getMessage());
    return "Fallback Result";
})
.thenAccept(result -> {
      System.out.println(result);
});

等待所有任务完成

allOf:等待所有给定的CompletableFutures 完成

CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 10);
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 20);

CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2);
// 当所有异步CompletableFuture执行完以后调用thenRun方法
allFutures.thenRun(() -> System.out.println("All tasks completed"));

任何一个完成即可继续

anyOf:当任意一个给定的CompletableFutures 完成时继续执行

CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 10);
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 20);

CompletableFuture<Object> anyOf = CompletableFuture.anyOf(future1, future2);
anyOf.thenAccept(result -> System.out.println("First completed task result: " + result));

线程池高效管理

默认情况下,supplyAsync 和 runAsync使用公共的ForkJoinPool。可以通过重载方法传入自定义线程池来提高性能,避免线程争用。

ExecutorService executor = Executors.newFixedThreadPool(10);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // 长时间运行的任务
    return "Result";
}, executor);
  • 尽量使用链式调用俩避免嵌套回调,使代码更具有可读性和可维护性
  • 合理使用异常方法处理来捕获和处理异步操作中的异常
public class AsyncExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(4);

        // 异步获取数据
        CompletableFuture<String> fetchData = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000); // 模拟延迟
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
            return "data";
        }, executor);

        // 转换数据并输出
        fetchData.thenApply(data -> "Processed " + data)
                 .thenAccept(System.out::println)
                 .exceptionally(ex -> {
                     System.err.println("Error: " + ex.getMessage());
                     return null;
                 });

        executor.shutdown();
    }
}