什么是 Java 的 CompletableFuture?

Sherwin.Wei Lv7

什么是 Java 的 CompletableFuture?

回答重点

CompletableFuture 是 Java 8 引入的一个强大的异步编程工具。允许非阻塞地处理异步任务,并且可以通过链式调用组合多个异步操作。

核心特性

  1. 异步执行:使用 runAsync()supplyAsync() 方法,可以非阻塞地执行任务。
  2. 任务的组合:可以使用 thenApply()thenAccept() 等方法在任务完成后进行后续操作,支持链式调用。
  3. 异常处理:提供 exceptionally()handle() 等方法来处理异步任务中的异常。
  4. 并行任务:支持多个异步任务的组合,如 thenCombine()allOf() 等方法,可以在多个任务完成后进行操作。
  5. 非阻塞获取结果:相比 FutureCompletableFuture 支持通过回调函数获取结果,而不需要显式的阻塞等待。

扩展知识

使用示例

创建异步任务

  • runAsync:创建异步任务,不返回结果
  • supplyAsync:创建异步任务并返回结果
1
2
3
4
5
6
7
8
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
// 异步任务
});

CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
// 异步任务并返回结果
return "Hello, mianshiya.com!";
});

任务完成回调

  • thenApply:在任务完成后可以对任务结果进行转换返回
  • thenAccept:在任务完成后对结果进行消费,但不返回新结果
  • thenRun:在任务完成后执行一个操作,但不需要使用任务结果
1
2
3
4
5
6
7
8
9
10
11
12
13

// 转换任务结果
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
.thenApply(result -> result + " mianshiya.com");

// 消费任务结果,不返回新结果
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> "Hello")
.thenAccept(result -> System.out.println(result));

// 不消费任务结果,也不返回新结果
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> "Hello")
.thenRun(() -> System.out.println("Task finished"));

任务组合

  • thenCombine:合并两个 CompletableFuture 的结果。
  • thenCompose:将一个 CompletableFuture 的结果作为另一个 CompletableFuture 的输入。
1
2
3
4
5
6
7
8
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "面试鸭");

CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (result1, result2) -> result1 + " " + result2);

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
.thenCompose(result -> CompletableFuture.supplyAsync(() -> result + " 面试鸭"));

异常处理

  • exceptionally:在任务发生异常时提供默认值。
  • handle:在任务完成或发生异常时进行处理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
if (true) {
throw new RuntimeException("Exception");
}
return "Hello";
}).exceptionally(ex -> "面试鸭");


CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
if (true) {
throw new RuntimeException("Exception");
}
return "Hello";
}).handle((result, ex) -> {
if (ex != null) {
return "Default Value";
}
return result;
});


并行处理

  • allOf:等待多个 CompletableFuture 全部完成
  • anyOf:任意一个 CompletableFuture 完成时执行操作
1
2
3
4
5
6
7
8

CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2);
allFutures.thenRun(() -> System.out.println("面试鸭 tasks finished"));


CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(future1, future2);
anyFuture.thenAccept(result -> System.out.println("面试鸭 task finished with result: " + result));

与 Future 的区别

Future 是 Java 5 引入的接口,提供了基本的异步处理功能,但它的局限性在于只能通过 get() 方法阻塞获取结果,无法链式调用多个任务,也缺少异常处理机制。

CompletableFutureFuture 的增强版,提供了非阻塞的结果处理、任务组合和异常处理,使得异步编程更加灵活和强大。

异步执行自定义线程池

默认情况下,CompletableFuture 使用 ForkJoinPool 作为线程池,可以通过自定义线程池提高性能或满足特定的并发需求。

例如:

1
2
Executor executor = Executors.newFixedThreadPool(10);
CompletableFuture.supplyAsync(() -> "result", executor);

异常处理的灵活性

CompletableFuture 提供了多种处理异常的方式,允许在异步任务中优雅地处理异常,避免代码复杂度提升。常见的异常处理方法有:

  • exceptionally()
  • handle()
Comments