Java并发编程框架之CompletableFuture

我们每个人都不会想自甘堕落,只是我们没法儿在保证生存之前去寻找自己的兴趣。做蛋糕我们要查食谱,研究蛋糕胚的配方,先加蛋白还是蛋清。养花我们也要查找资料,明白什么时候是合适的光照时间。就算是为了变美去健身化妆我们也会去尝试去实践,这些全都是在学习!并且这些兴趣完成的步骤是清晰的,就像是玩游戏做任务一样,每一步你都知道该怎么干。考试痛苦的是没有成就感和迷茫,被每一次成绩打击,我一直觉得考研读研对于大部分人来说是个违背人性的过程(只是我自己觉得,也有学习天赋特别好的大佬觉得这是个轻松的过程),只是我们为了工作生存不得不进入社会给我们安排的入场考核。


目录

 介绍

优点

示例代码

使用.thenApply()

使用.thenCompose()

CompletableFuture`还有哪些方法

创建类

状态取值类

控制类

接续类

组合类


 介绍

CompletableFuture是Java 8引入的一个强大类,它不仅扩展了Future接口的功能,还实现了CompletionStage接口,从而提供了更加丰富的方法来处理异步操作和任务组合。CompletableFuture允许开发者以声明式的方式构建异步操作流水线,并且能够轻松地将多个异步任务串联起来执行。此外,它也支持与阻塞I/O等其他类型的操作相结合,这使得编写非阻塞、响应式的应用程序变得更加容易。

优点

  • 丰富的组合器方法CompletableFuture提供了一系列的方法,如thenApply()thenCompose()allOf()anyOf()等,用于组合不同的异步任务。
  • 链式调用:由于这些方法返回的是CompletableFuture对象本身,因此可以方便地进行链式调用,简化代码结构。
  • 异常处理:提供了exceptionally()handle()whenComplete()等方法来处理可能发生的异常情况,确保即使在错误发生时也能保持良好的用户体验。

示例代码

接下来我们将通过几个具体的例子来展示如何使用CompletableFuture.thenApply().thenCompose()方法来串联多个异步步骤。

使用.thenApply()

.thenApply()方法用于在前一个CompletableFuture完成后对其结果应用一个函数,并返回一个新的CompletableFuture,该CompletableFuture包含转换后的结果。下面的例子展示了如何使用.thenApply()方法来对两个异步任务的结果进行处理:

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 异步获取字符串
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("Task 1 running...");
            try { Thread.sleep(1000); } catch (InterruptedException e) { /* ignored */ }
            return "Hello";
        });

        // 对future1的结果进行转换
        CompletableFuture<String> future2 = future1.thenApply(result -> {
            System.out.println("Transforming result of Task 1...");
            return result + " World!";
        });

        // 打印最终结果
        System.out.println("Final result: " + future2.get());
    }
}

在这个例子中,我们首先创建了一个异步任务future1,它会在完成之后返回字符串"Hello"。然后我们使用.thenApply()方法接收future1的结果,并将其转换为"Hello World!"。最后,我们调用了.get()方法来获取并打印最终的结果。

使用.thenCompose()

当需要根据前一个异步任务的结果启动另一个新的异步任务时,可以使用.thenCompose()方法。这个方法接受一个函数作为参数,该函数返回一个新的CompletableFuture。下面是一个简单的例子,说明了如何使用.thenCompose()方法来实现这样的逻辑:

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureComposeExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 模拟异步获取用户信息
        CompletableFuture<String> getUserInfo = CompletableFuture.supplyAsync(() -> {
            System.out.println("Fetching user info...");
            try { Thread.sleep(500); } catch (InterruptedException e) { /* ignored */ }
            return "User Info";
        });

        // 根据用户信息发起另一个异步请求
        CompletableFuture<String> processUserInfo = getUserInfo.thenCompose(userInfo -> {
            System.out.println("Processing user info...");
            return CompletableFuture.supplyAsync(() -> {
                try { Thread.sleep(500); } catch (InterruptedException e) { /* ignored */ }
                return "Processed " + userInfo;
            });
        });

        // 获取并打印最终结果
        System.out.println("Final result: " + processUserInfo.get());
    }
}

这里,getUserInfo代表了一个异步任务,它负责从某个地方(比如数据库)获取用户信息。一旦这个任务完成了,我们就想基于获取到的信息再发起一次新的异步请求——即processUserInfo。为了实现这一点,我们在getUserInfo后面添加了.thenCompose()方法,它会等待前面的任务结束,并根据其输出启动下一个异步任务。最终,我们再次调用.get()方法来获得整个流程的结果。

CompletableFuture`还有哪些方法

CompletableFuture 提供了多种方法来支持异步编程,这些方法可以分为几大类:创建、状态取值、控制执行、接续行为(即回调),以及组合多个异步任务。下面将详细介绍 CompletableFuture 的其他重要方法。

创建类

  • supplyAsync(Supplier<U> supplier) 和 supplyAsync(Supplier<U> supplier, Executor executor):用于创建带有返回值的异步任务。前者使用默认线程池(ForkJoinPool.commonPool()),而后者允许指定自定义的线程池。
  • runAsync(Runnable runnable) 和 runAsync(Runnable runnable, Executor executor):创建没有返回值的异步任务,同样地,可以选择使用默认或自定义线程池。

状态取值类

  • get():阻塞等待任务完成并获取结果,如果任务抛出了异常,则会重新抛出该异常。
  • get(long timeout, TimeUnit unit):与 get() 类似,但是增加了超时机制,如果在指定时间内未完成则抛出 TimeoutException
  • join():非阻塞地尝试获取结果,如果任务已经完成则立即返回结果;否则等待直到任务完成或抛出异常。

控制类

  • complete(T value) 和 completeExceptionally(Throwable ex):手动完成一个 CompletableFuture 实例,分别用于正常完成和异常完成的情况。
  • cancel(boolean mayInterruptIfRunning):取消尚未开始的任务,参数指定了是否中断正在运行的任务。

接续类

接续类的方法主要用于定义当某个 CompletableFuture 完成后应该做什么,它们通常接受函数式接口作为参数,并根据需要返回新的 CompletableFuture 实例。

  • thenApply(Function<? super T,? extends U> fn) 和 thenApplyAsync(...):对结果应用一个函数,并返回一个新的包含转换后结果的 CompletableFuture
  • thenAccept(Consumer<? super T> action) 和 thenAcceptAsync(...):接收结果但不返回任何值,适用于只需要处理结果而不关心后续步骤的情形。
  • thenRun(Runnable action) 和 thenRunAsync(...):无论前一个阶段的结果是什么,都会执行给定的动作,且不产生输出。
  • whenComplete(BiConsumer<? super T,? super Throwable> action) 和 whenCompleteAsync(...):无论成功还是失败,都会调用提供的动作,并传递结果和可能发生的异常。
  • handle(BiFunction<? super T,Throwable,? extends U> fn) 和 handleAsync(...):类似于 whenComplete,但它还允许基于结果或异常返回一个新的值。

组合类

为了更好地组织多个异步任务,CompletableFuture 还提供了若干用于组合多个 CompletableFuture 的方法:

  • thenCompose(Function<? super T,? extends CompletionStage<U>> fn) 和 thenComposeAsync(...):用于扁平化链式调用,确保只有当第一个任务完成后才会启动第二个任务。
  • thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn) 和 thenCombineAsync(...):合并两个已完成的任务的结果,并通过提供的函数生成第三个结果。
  • allOf(CompletableFuture<?>... cfs):等待所有给定的 CompletableFuture 都完成,但不会直接提供它们的结果。可以通过 join() 或 get() 方法获取整体状态。
  • anyOf(CompletableFuture<?>... cfs):只要任何一个 CompletableFuture 完成就立即返回,它会携带最先完成的那个 CompletableFuture 的结果。

综上所述,CompletableFuture 提供了一套全面的方法来简化异步编程中的常见需求,如创建异步任务、管理任务的状态、定义任务完成后的回调逻辑,以及高效地组合多个异步任务以实现复杂的业务流程。这使得 Java 开发者能够在保持代码简洁的同时,充分利用多核处理器的优势,提高应用程序性能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程星辰海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值