学习理解 CompletableFuture
CompletableFuture
是 Java 8 引入的一个强大的工具,它使得编写异步和并行代码变得更加容易。
CompletableFuture
是 java.util.concurrent
包的一部分,是 Future
的扩展,它不仅允许你手动完成计算,还提供了一套丰富的 API 来支持异步编程。与传统的 Future
不同,CompletableFuture
提供了非阻塞的方式来获取结果,并且可以链式调用和组合多个异步任务。
和 Future
对比
上一篇文章详细介绍了Future
类,请看 学习Java中的Future类: https://blog.csdn.net/kaka_buka/article/details/139663543
Future
和 CompletableFuture
都是 Java 中用于表示异步计算结果的接口,但它们之间有一些重要的区别:
-
获取结果:
Future
:需要调用get()
方法来阻塞当前线程,直到计算完成。CompletableFuture
:提供了非阻塞的thenApply
,thenAccept
等方法来处理结果,允许在任务完成后自动执行回调。
-
组合任务:
Future
:没有直接支持任务组合的机制,需要手动管理多个Future
。CompletableFuture
:提供了丰富的方法来组合多个异步任务,例如thenCompose
,thenCombine
,allOf
,anyOf
等。
-
异常处理:
Future
:没有直接支持异常处理,需要在get()
方法调用时捕获异常。CompletableFuture
:提供了exceptionally
,handle
等方法来处理异步任务中的异常。
通过以上对比可以看出,CompletableFuture
在异步编程中的灵活性和功能性远远超过了传统的 Future
。
创建 CompletableFuture
1. 使用静态方法创建
CompletableFuture
提供了几种静态方法来创建其实例:
CompletableFuture.supplyAsync(Supplier<U> supplier)
:异步地执行一个返回值的任务。CompletableFuture.runAsync(Runnable runnable)
:异步地执行一个不返回值的任务。
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
// 异步任务,不返回结果
System.out.println("Running in a separate thread");
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
// 异步任务,返回结果
return "Hello, CompletableFuture!";
});
2. 手动完成 CompletableFuture
你也可以创建一个空的 CompletableFuture
实例,并在未来的某个时间点手动完成它:
CompletableFuture<String> future = new CompletableFuture<>();
// 在某个时刻手动完成
future.complete("Manual completion");
常用方法
CompletableFuture
提供了丰富的方法来处理异步任务,下面介绍几种常用的方法:
1. thenApply
thenApply
方法用于在前一个任务完成后,对结果进行转换:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
.thenApply(result -> result + " World");
2. thenAccept
thenAccept
方法用于在前一个任务完成后,处理结果但不返回新的结果:
CompletableFuture.supplyAsync(() -> "Hello")
.thenAccept(result -> System.out.println("Result: " + result));
3. thenRun
thenRun
方法用于在前一个任务完成后,执行一个新的任务,但不依赖于前一个任务的结果:
CompletableFuture.supplyAsync(() -> "Hello")
.thenRun(() -> System.out.println("Task completed"));
4. handle
handle
方法用于处理任务的结果或异常:
CompletableFuture.supplyAsync(() -> {
if (new Random().nextBoolean()) {
throw new RuntimeException("Failed");
}
return "Success";
}).handle((result, ex) -> {
if (ex != null) {
return "Error: " + ex.getMessage();
}
return result;
});
组合多个 CompletableFuture
CompletableFuture
允许你组合多个异步任务,以下是几种常见的组合方式:
1. thenCompose
thenCompose
用于将多个异步任务进行平铺,使其顺序执行:
CompletableFuture.supplyAsync(() -> "Hello")
.thenCompose(result -> CompletableFuture.supplyAsync(() -> result + " World"));
2. thenCombine
thenCombine
用于将两个并行执行的异步任务的结果合并:
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");
future1.thenCombine(future2, (result1, result2) -> result1 + " " + result2);
3. allOf
allOf
用于等待所有给定的 CompletableFuture
都完成:
CompletableFuture<Void> allOfFutures = CompletableFuture.allOf(future1, future2);
allOfFutures.thenRun(() -> System.out.println("All tasks completed"));
4. anyOf
anyOf
用于等待任意一个给定的 CompletableFuture
完成:
CompletableFuture<Object> anyOfFutures = CompletableFuture.anyOf(future1, future2);
anyOfFutures.thenAccept(result -> System.out.println("First completed task result: " + result));
异常处理
在使用 CompletableFuture
时,处理异常是至关重要的。CompletableFuture
提供了几种方法来处理异步任务中的异常:
exceptionally
exceptionally
方法用于在计算过程中发生异常时提供一个默认值:
CompletableFuture.supplyAsync(() -> {
if (new Random().nextBoolean()) {
throw new RuntimeException("Failed");
}
return "Success";
}).exceptionally(ex -> "Error: " + ex.getMessage());
handle
前面提到的 handle
方法也可以用于处理异常,同时还可以处理正常的结果:
CompletableFuture.supplyAsync(() -> {
if (new Random().nextBoolean()) {
throw new RuntimeException("Failed");
}
return "Success";
}).handle((result, ex) -> {
if (ex != null) {
return "Error: " + ex.getMessage();
}
return result;
});
结论
CompletableFuture
为 Java 异步编程提供了强大的支持,它不仅简化了异步任务的编写,还提供了丰富的 API 来组合多个任务和处理异常。在现代 Java 应用中,CompletableFuture
是一个不可或缺的工具。
参考链接
- CompletableFuture 官方文档
- Java 并发编程教程
- Java 8 Concurrency Tutorial: Threads and Executors