CompletableFuture 详解
CompletableFuture 是 Java 8 引入的一个类,位于 java.util.concurrent 包中,它支持异步编程,并且提供了比传统的 Future 更强大的功能。CompletableFuture 既可以用于异步任务的执行,也可以用于实现组合多个异步任务、处理异步结果以及异常处理等复杂操作。
CompletableFuture 实现了 Future 接口,同时它还提供了丰富的 API 来执行异步计算、注册回调函数、进行多线程组合等。
1. CompletableFuture 基本概念
CompletableFuture 是一个可组合的异步任务。当一个任务异步执行完毕时,它会将结果提供给注册的回调函数。通过 CompletableFuture,可以组合多个异步任务,轻松处理并发任务之间的依赖关系。
2. 创建 CompletableFuture
2.1 使用 supplyAsync 启动异步任务
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
return 100;
});supplyAsync会异步执行传入的Supplier任务,并返回一个CompletableFuture对象。
2.2 使用 runAsync 启动无返回值的异步任务
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
// 执行异步任务,不需要返回值
System.out.println("Task executed");
});runAsync用于执行一个无返回值的异步任务。
2.3 创建已完成的 CompletableFuture
CompletableFuture<Integer> completedFuture = CompletableFuture.completedFuture(42);completedFuture创建一个已完成的CompletableFuture,并返回指定的结果。
3. 异步任务的组合
3.1 thenApply:转换返回值
thenApply 用于对任务的返回值进行转换,它会在原任务完成后执行,并返回一个新的结果。
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 100)
.thenApply(result -> result * 2); // 将返回值乘以 2thenApply返回一个新的CompletableFuture,该CompletableFuture会在前一个任务完成后执行,并对返回的结果进行处理。
3.2 thenAccept:消费返回值
thenAccept 用于对结果进行消费,但不返回结果。
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> "Hello")
.thenAccept(result -> System.out.println("Processed: " + result));thenAccept是一种无返回值的操作,它仅对结果进行消费操作。
3.3 thenRun:后续任务
thenRun 用于执行一个没有输入参数的后续操作,后续操作不会使用前一个任务的结果。
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> 100)
.thenRun(() -> System.out.println("Task completed"));thenRun可以在前一个任务完成后执行某个操作,但没有输入参数。
3.4 thenCombine:合并两个异步任务的结果
thenCombine 可以将两个独立的异步任务的结果合并起来进行后续处理。
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 10);
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 20);
CompletableFuture<Integer> result = future1.thenCombine(future2, (res1, res2) -> res1 + res2);thenCombine返回一个新的CompletableFuture,它会等到两个原任务完成,然后合并它们的结果。
3.5 thenCompose:扁平化异步任务
thenCompose 用于将多个异步任务串联起来,后续任务依赖前一个任务的结果,返回一个新的 CompletableFuture。
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 100)
.thenCompose(result -> CompletableFuture.supplyAsync(() -> result * 2));thenCompose适用于处理返回类型为CompletableFuture的异步任务,从而避免了多层嵌套。
3.6 allOf:等待所有任务完成
allOf 用于等待多个 CompletableFuture 任务同时完成,并返回一个新的 CompletableFuture<Void>。
CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(future1, future2);allOf适用于多个任务并行执行的场景,等待所有任务完成后再执行后续操作。
3.7 anyOf:等待任意一个任务完成
anyOf 用于等待多个 CompletableFuture 中的任意一个任务完成,并返回一个新的 CompletableFuture,它会以第一个完成的任务的结果为结果。
CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(future1, future2);anyOf适用于多个任务中只需要一个成功的场景。
4. 异常处理
CompletableFuture 提供了多个方法来处理异步任务中的异常。
4.1 exceptionally:异常处理
exceptionally 用于处理 CompletableFuture 执行过程中出现的异常,并返回一个默认值。
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
throw new RuntimeException("Exception");
}).exceptionally(ex -> {
System.out.println("Exception occurred: " + ex.getMessage());
return 0; // 返回默认值
});exceptionally可以捕获并处理异常,返回一个默认的值来继续执行后续操作。
4.2 handle:处理结果和异常
handle 用于同时处理结果和异常,可以根据任务是否成功执行来决定返回什么结果。
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 100)
.handle((result, ex) -> {
if (ex != null) {
System.out.println("Error: " + ex.getMessage());
return -1;
}
return result * 2;
});handle方法会在任务完成后执行,无论任务是正常完成还是异常结束。
4.3 whenComplete:在任务完成后处理
whenComplete 会在任务完成后执行,无论是正常完成还是出现异常。它与 handle 相似,但是 whenComplete 不允许修改返回值。
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 100)
.whenComplete((result, ex) -> {
if (ex != null) {
System.out.println("Error occurred: " + ex.getMessage());
} else {
System.out.println("Completed with result: " + result);
}
});whenComplete仅用于任务的后处理,不改变结果。
5. 阻塞方法
尽管 CompletableFuture 提供了异步编程的强大支持,但也提供了阻塞方法,允许你获取最终结果。
5.1 get()
Integer result = future.get(); // 阻塞直到任务完成,获取结果get()会阻塞当前线程,直到CompletableFuture完成并返回结果。
5.2 join()
Integer result = future.join(); // 阻塞直到任务完成,获取结果join()与get()类似,但是join()会捕获并包装异常为CompletionException,而get()会抛出原始的ExecutionException。
5.3 getNow()
Integer result = future.getNow(0); // 如果任务已经完成,返回结果;否则返回指定的默认值getNow()会返回当前结果,或者如果任务尚未完成,则返回一个默认值。
6. 使用场景
- 异步计算:执行需要时间的任务,如文件下载、网络请求、数据库操作等。
- 异步任务组合:当多个任务之间存在依赖关系或需要组合时,可以通过
thenApply、thenCombine等方法将它们组合起来。 - 并行执行:多个独立的异步任务可以并行执行,通过
allOf或anyOf等方法等待多个任务的完成。 - 异常处理:可以在异步任务中方便地处理异常,通过
exceptionally、handle等方法保证任务的健壮性。
总结
CompletableFuture 是 Java 提供的用于异步编程的工具,它提供了比传统 Future 更强大的功能,支持任务组合、异常处理和多线程同步等功能。
