CompletableFuture异步编程Api使用详解

news2024/12/23 11:53:00

Java 8 引入了很多的新特性,其中就包含了 CompletableFuture 类的引入,它允许我们通过在与主应用程序线程不同的线程上(也就是异步)运行任务,并向主线程通知任务的进度、完成或失败,来编写非阻塞代码。

Future的局限性

从本质上说,Future表示一个异步计算的结果。它提供了isDone()来检测计算是否已经完成,并且在计算结束后,可以通过get()方法来获取计算结果。在异步计算中,Future确实是个非常优秀的接口。但是,它的本身也确实存在着许多限制:并发执行多任务:Future只提供了get()方法来获取结果,并且是阻塞的。所以,除了等待你别无他法;无法对多个任务进行链式调用:如果你希望在计算任务完成后执行特定动作,比如发邮件,但Future却没有提供这样的能力;无法组合多个任务:如果你运行了10个任务,并期望在它们全部执行结束后执行特定动作,那么在Future中这是无能为力的;没有异常处理:Future接口中没有关于异常处理的方法;

CompleteableFuture

简单的任务,用Future获取结果还好,但我们并行提交的多个异步任务,往往并不是独立的,很多时候业务逻辑处理存在串行[依赖]、并行、聚合的关系。如果要我们手动用 Fueture 实现,是非常麻烦的。

JDK1.8 才新加入的一个实现类 CompletableFuture,实现了 Future,CompletionStage两个接口。实现了 Future 接口,意味着可以像以前一样通过阻塞或者轮询的方式获得结果。

CompletableFuture是Future接口的扩展和增强。CompletableFuture实现了Future接口,并在此基础上进行了丰富地扩展,完美地弥补了Future上述的种种问题。更为重要的是,CompletableFuture实现了对任务的编排能力。借助这项能力,我们可以轻松地组织不同任务的运行顺序、规则以及方式。从某种程度上说,这项能力是它的核心能力。而在以往,虽然通过CountDownLatch等工具类也可以实现任务的编排,但需要复杂的逻辑处理,不仅耗费精力且难以维护。

为什么要引入 CompletableFuture

Java 的 1.5 版本引入了 Future,你可以把它简单的理解为运算结果的占位符,它提供了两个方法来获取运算结果。
get():调用该方法线程将会无限期等待运算结果。get(long timeout, TimeUnit unit):调用该方法线程将仅在指定时间 timeout 内等待结果,如果等待超时就会抛出 TimeoutException 异常。

Future 可以使用 Runnable 或 Callable 实例来完成提交的任务,通过其源码可以看出,它存在如下几个问题: 阻塞 调用 get() 方法会一直阻塞,直到等待直到计算完成,它没有提供任何方法可以在完成时通知,同时也不具有附加回调函数的功能。链式调用和结果聚合处理 在很多时候我们想链接多个 Future 来完成耗时较长的计算,此时需要合并结果并将结果发送到另一个任务中,该接口很难完成这种处理。异常处理 Future 没有提供任何异常处理的方式。

以上这些问题在 CompletableFuture 中都已经解决了,接下来让我们看看如何去使用 CompletableFuture。

常用方法

依赖关系

thenApply():把前面任务的执行结果,交给后面的Function
thenCompose():用来连接两个有依赖关系的任务,结果由第二个任务返回

and集合关系

thenCombine():合并任务,有返回值
thenAccepetBoth():两个任务执行完成后,将结果交给thenAccepetBoth处理,无返回值
runAfterBoth():两个任务都执行完成后,执行下一步操作(Runnable类型任务)

or聚合关系

applyToEither():两个任务哪个执行的快,就使用哪一个结果,有返回值
acceptEither():两个任务哪个执行的快,就消费哪一个结果,无返回值
runAfterEither():任意一个任务执行完成,进行下一步操作(Runnable类型任务)

并行执行

allOf():当所有给定的 CompletableFuture 完成时,返回一个新的 CompletableFuture
anyOf():当任何一个给定的CompletablFuture完成时,返回一个新的CompletableFuture

结果处理

whenComplete:当任务完成时,将使用结果(或 null)和此阶段的异常(或 null如果没有)执行给定操作
exceptionally:返回一个新的CompletableFuture,当前面的CompletableFuture完成时,它也完成,当它异常完成时,给定函数的异常触发这个CompletableFuture的完成

异步操作

CompletableFuture提供了四个静态方法来创建一个异步操作:

public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

这方法的区别:
1)runAsync() 以Runnable函数式接口类型为参数,没有返回结果。
2)supplyAsync() 以Supplier函数式接口类型为参数,返回结果类型为U;

异步操作

Runnable runnable = () -> System.out.println("无返回结果异步任务");
CompletableFuture.runAsync(runnable);

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    System.out.println("有返回值的异步任务");
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "Hello World";
});
String result = future.get();

获取结果(join&get)

join()和get()方法都是用来获取CompletableFuture异步之后的返回值。join()方法抛出的是uncheck异常(即未经检查的异常),不会强制开发者抛出。get()方法抛出的是经过检查的异常,ExecutionException, InterruptedException 需要用户手动处理(抛出或者 try catch)
结果处理

当CompletableFuture的计算结果完成,或者抛出异常的时候,我们可以执行特定的 Action。主要是下面的方法:

public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)

Action的类型是BiConsumer<? super T,? super Throwable>,它可以处理正常的计算结果,或者异常情况。方法不以Async结尾,意味着Action使用相同的线程执行,而Async可能会使用其它的线程去执行(如果使用相同的线程池,也可能会被同一个线程选中执行)。
这几个方法都会返回CompletableFuture,当Action执行完毕后它的结果返回原始的CompletableFuture的计算结果或者返回异常。

应用场景

描述依赖关系:

thenApply() 把前面异步任务的结果,交给后面的FunctionthenCompose()用来连接两个有依赖关系的任务,结果由第二个任务返回

描述and聚合关系:

thenCombine:任务合并,有返回值thenAccepetBoth:两个任务执行完成后,将结果交给thenAccepetBoth消耗,无返回值。runAfterBoth:两个任务都执行完成后,执行下一步操作(Runnable)。

描述or聚合关系:

applyToEither:两个任务谁执行的快,就使用那一个结果,有返回值。acceptEither: 两个任务谁执行的快,就消耗那一个结果,无返回值。runAfterEither: 任意一个任务执行完成,进行下一步操作(Runnable)。

并行执行:

CompletableFuture类自己也提供了anyOf()和allOf()用于支持多个CompletableFuture并行执行

总结 CompletableFuture 几个关键点:

1、计算可以由 Future ,Consumer 或者 Runnable 接口中的 apply,accept或者 run 等方法表示。

2、计算的执行主要有以下

a. 默认执行

b. 使用默认的 CompletionStage 的异步执行提供者异步执行。这些方法名使用 someActionAsync 这种格式表示。

c. 使用 Executor 提供者异步执行。这些方法同样也是 someActionAsync 这 种格式,但是会增加一个 Executor 参数。

CompletableFuture的API非常丰富,不用全部掌握,大概了解有哪些功能,使用时会查API就行。
在这里插入图片描述在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/22322.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LVS-DR模式部署

目录 一、环境准备 1、DR模式介绍 2、DR模式工作原理 3、服务器准备 二、实验拓扑 三、配置网络环境 1、配置调度器网络环境 2、配置Web服务器网络环境 四、创建LVS-DR集群 1、创建LVS集群 2、添加Real Server 3、查看lvs配置 五、LVS服务器开启路由转发 六、效果…

TCP四次挥手 2MSL TIME_WAIT详解

TCP四次挥手 & 2MSL & TIME_WAIT详解TCP四次挥手流程各状态解析2MSL(2倍最大报文段生成时间)2MSL (Maximum Segment Lifetime) TIME_WAIT状态的存在有两个理由该状态为什么设计在主动关闭这一方?如何正确对待2MSL TIME_WAIT?TCP四次挥手流程 【注意】只要是申请关闭连…

基于Open vSwitch的传统限速和SDN限速--实验

基于Open vSwitch的传统限速和SDN限速--实验基于Open vSwitch的传统限速和SDN限速--实验1.下载与安装1.1 安装Docker1.2 Open vSwitch的安装2.配置实验环境3.实验步骤3.1启动floodlight控制器3.2创建拓扑3.3网卡限速3.4队列限速3.5 Meter表限速4.三种方式数据对比5.实验分析6.总…

仿大众点评——秒杀系统部分03——RabbitMq措施

RabbitMq保证消息不丢失 RabbitMQ如何保证消息的可靠性&#xff1a; 1.从生产者到消息队列&#xff0c;congfirm模式&#xff08;与事务相比confirm模式最大的优势是异步&#xff09;通过消息确认机制来保证&#xff0c;通过给每个指派唯一标志&#xff0c;完成消费后返回ack确…

【LeetCode每日一题】——136.只出现一次的数字

文章目录一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【解题思路】七【题目提示】八【时间频度】九【代码实现】十【提交结果】一【题目类别】 数组 二【题目难度】 简单 三【题目编号】 136.只出现一次的数字 四【题目描述】 给你一个 非…

[附源码]SSM计算机毕业设计风景区管理系统JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

再学DataX

一、DataX简介 DataX官网文档&#xff1a;https://github.com/alibaba/DataX/blob/master/introduction.md DataX 是一个异构数据源离线同步工具&#xff0c;致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定高效的数据同…

MyBatis基于XML的使用——动态sql

1、动态sql 动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它 类似的框架&#xff0c;你应该能理解根据不同条件拼接 SQL 语句有多痛苦&#xff0c;例如拼接时要确保不能忘记添加必要的空格&#xff0c;还要注意去掉列表最后一个列名的逗号。 利用动态 SQL&#…

14服务-ClearDiagnosticlnformation

诊断协议那些事儿 诊断协议那些事儿专栏系列文章&#xff0c;本文介绍存储数据传输服务下的14服务ClearDiagnosticlnformation&#xff0c;客户端使用ClearDiagnosticlnformation服务清除一个或多个服务器存储器中的诊断信息。 关联文章&#xff1a;$19服务:DTCStatusMask和s…

CockroachDB-读和写

本文知识点来源于官网地址https://www.cockroachlabs.com/docs/stable/architecture/reads-and-writes-overview.html 查询执行 当CRDB执行查询时&#xff0c;集群将请求路由到包含相关数据的范围的Leaseholder。如果查询涉及多个范围&#xff0c;则请求将发送给多个Leasehol…

求实数的整数次幂(循环版)(高效)(位运算解题)

求实数的整数次幂(循环版)(高效) (10 分) 原理图&#xff1a; 请编写函数&#xff0c;用循环语句以最快的方法求任意实数的任意整数次幂。 函数原型 double Power(double x, int n); 说明&#xff1a;参数 x 为底数&#xff0c;n 为指数。若参数正确&#xff0c;则函数值为…

智能驾驶开启产业新赛道:资本扎堆布局车规级高精定位

2022年被称为高阶智能驾驶元年的背后&#xff0c;新的产业链正在悄然发展。 车规级高精定位便是其中之一。2022年10月&#xff0c;主业聚焦于动力总成测试的上海华依科技集团股份有限公司&#xff08;以下简称“华依科技”&#xff0c;688071.SH&#xff09;&#xff0c;发布公…

漫画风格迁移神器 AnimeGANv2:快速生成你的漫画形象

生成你的漫画形象&#xff01; 漫画风格迁移神器 AnimeGANv2 文章目录生成你的漫画形象&#xff01; 漫画风格迁移神器 AnimeGANv2快速在线生成你的漫画形象AnimeGAN 简要介绍与其他动漫风格迁移模型的效果对比AnimeGANv2 的优点AnimeGANv2 风格多样化AnimeGANv2 网络结构快速生…

基于stm32单片机的水位检测自动抽水系统

资料编号&#xff1a;106 下面是相关功能视频演示&#xff1a; 106-基于stm32单片机的水位检测自动抽水系统Proteus仿真&#xff08;源码仿真全套资料&#xff09;功能介绍&#xff1a; 使用滑动变阻器模拟水位监测器&#xff0c;通过改变电压值表示水位的变化。stm32通过ADC…

【前端】从 0 到 1 实现一个网站框架(一、注册 [1] )

Hi~你好呀&#xff0c;等你很久啦~ 我是 LStar&#xff0c;一枚来自北京的初二女生&#xff0c;2020 年年初加入 CSDN。 话不多说&#xff0c;直入主题~&#xff08;我现在看两年多前我 11 岁那会发的文章&#xff0c;越看越想笑。为了不让四年后 18 岁的我看着这篇文章露出 …

超详细的mysql多表操作教程

目录 外键约束 概念 特点 操作 多表联合查询 概念 操作 多表操作总结 外键约束 概念 特点 定义一个外键时&#xff0c;需要遵守下列规则&#xff1a; 主表必须已经存在于数据库中&#xff0c;或者是当前正在创建的表。 必须为主表定义主键。 主键不能包含空值&#xf…

967亿销售额!博世解码智能汽车新蓝图

随着新一轮科技革命和产业变革的深化&#xff0c;在低碳化、电动化和智能化的推动下&#xff0c;处于变革关键时期的新能源汽车产业&#xff0c;正逐步由“政策驱动”转向“市场驱动”&#xff0c;智能化、网联化成为新趋势。 据中国汽车工业协会统计&#xff0c;今年我国新能…

通过 Traefik Hub 暴露家里的网络服务

Traefik Hub 简介 &#x1f4da;️Reference: 你的云原生网络平台 -- 发布和加固你的容器从未如此简单。 Traefik Hub 为您在 Kubernetes 或其他容器平台上运行的服务提供一个网关。 Traefik Hub 定位&#xff1a; 云原生网络平台 它有 2 大核心功能&#xff0c;我这次体验感…

pytorch深度学习实战lesson23

第二十三课 AlexNet AlexNet是在2012年被发表的一个金典之作&#xff0c;并在当年取得了ImageNet最好成绩&#xff0c;也是在那年之后&#xff0c;更多的更深的神经网路被提出&#xff0c;比如优秀的vgg,GoogleLeNet. 其官方提供的数据模型&#xff0c;准确率达到57.1%,top 1-5…

认识计算机中的简单指令集

我们现在有了一个新的寄存器&#xff0c;叫做指令寄存器。它包含一个字节&#xff0c;不同的内容表示控制部分的不同操作模式。也被称为指令代码。指令寄存器是一个字节&#xff0c;因此可能有多达256条不同的指令。所有指令都涉及在总线上移动字节。指令将导致字节进出RAM&…