掘金 后端 ( ) • 2024-04-11 10:45

CompletableFuture 是Java 8引入的一个类,它实现了Future接口和CompletionStage接口,提供了异步编程的能力。CompletableFuture可以用来编写非阻塞的代码,并且可以通过链式调用来组合多个异步操作。

原理:

CompletableFuture的核心原理是在计算完成时触发依赖动作的执行。它包含了一系列的完成阶段(completion stages),每个阶段都是计算的一步,可以同步或异步地执行。当一个阶段的计算完成时,它可以触发一个或多个后续阶段的执行。

CompletableFuture使用ForkJoinPool作为其默认的异步执行机制,但也可以指定其他的Executor来执行异步任务。它提供了多种方法来创建、完成、组合和处理异步计算的结果。

CompletableFuture 的高级用法:

1. 组合多个 CompletableFuture

-thenCombinethenCombineAsync:允许你将两个异步计算的结果合并成一个。

-thenComposethenComposeAsync:允许你将一个异步计算的结果作为另一个异步计算的输入。

2. 处理异步结果

-thenApplythenApplyAsync:允许你对异步计算的结果进行处理和转换。

  • thenAcceptthenAcceptAsync:允许你对异步计算的结果执行某些操作,但不返回结果。

-thenRunthenRunAsync:在两个阶段都执行完后,执行一个 Runnable,不关心前一个结果。

3. 处理异常

-exceptionally:允许你处理异步操作中的异常,并返回一个替代的结果。

-handlehandleAsync:允许你处理异步操作的结果或异常。

4. 异步操作的组合

-allOf:等待所有给定的 CompletableFuture 对象完成。

-anyOf:等待给定的 CompletableFuture 对象中的任意一个完成。

5. 异步执行任务

-runAsync:异步执行一个 Runnable 任务。

-supplyAsync:异步执行一个 Supplier 任务,并返回一个 CompletableFuture 以获取结果。

6. 响应 CompletableFuture 的完成

-whenCompletewhenCompleteAsync:在 CompletableFuture 完成时执行一个动作。

7. 使用自定义 Executor

  • 通过提供一个 Executor,你可以控制异步任务的执行,例如定义线程池的大小。

8. 延迟执行和超时

-orTimeout:如果 CompletableFuture 在指定时间内未完成,则完成它并抛出 TimeoutException

-completeOnTimeout:如果 CompletableFuture 在指定时间内未完成,则用默认值完成它。

示例代码:

创建一个异步操作

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 模拟长时间运行的异步任务
    sleep(1000);
    return "Hello";
});

使用 thenApply 对异步结果进行处理

CompletableFuture<String> greetingFuture = future.thenApply(name -> name + ", World!");

组合两个独立的 CompletableFuture

CompletableFuture<String> combinedFuture = greetingFuture.thenCombine(
    CompletableFuture.supplyAsync(() -> " from CompletableFuture!"),
    (greeting, addition) -> greeting + addition
);

处理最终结果或异常

combinedFuture.whenComplete((result, ex) -> {
    if (ex != null) {
        System.out.println("Something went wrong: " + ex.getMessage());
    } else {
        System.out.println(result); // 输出 "Hello, World! from CompletableFuture!"
    }
});

超时异常:

import java.util.concurrent.*;
public class CompletableFutureExample {

public static void main(String[] args) {

        // 创建一个将在未来某个时间点完成的 CompletableFuture
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            // 模拟一个长时间运行的任务
            try {
                TimeUnit.SECONDS.sleep(5); // 假设任务需要5秒钟完成
            } catch (InterruptedException e) {
Thread.currentThread().interrupt();
            }
            return "任务结果";
        });
// 设置超时时间为3秒,如果超时则返回默认值 "超时默认值"

CompletableFuture<String> timeoutFuture = future.completeOnTimeout("超时默认值", 3, TimeUnit.SECONDS);
// 获取最终结果,不会抛出异常,如果超时则返回 "超时默认值"

        try {
            String result = timeoutFuture.get(); // 这里会阻塞直到 future 完成或超时
            System.out.println(result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

总结:

在上面的代码中,我们创建了一个 CompletableFuture,它将在5秒后完成。然后我们使用 completeOnTimeout 方法设置了一个3秒的超时时间,并指定了一个超时后的默认返回值 "超时默认值"。
由于原始的 CompletableFuture 需要5秒才能完成,但我们设置了3秒的超时,所以 timeoutFuture 将会在3秒后由于超时而返回 "超时默认值"。

请注意,completeOnTimeout 方法是在 Java 9 及更高版本中引入的,如果你使用的是 Java 8 或更低版本,那么这个方法是不可用的

使用 CompletableFuture 的高级用法可以帮助你构建复杂的异步逻辑,优化性能,并提高代码的可读性和可维护性。CompletableFuture提供了强大的工具集来处理复杂的异步逻辑。通过合理使用这些工具,可以构建出高效、可读性好、易于维护的异步程序。