如何使用CompletableFuture

news2024/11/29 20:51:05

目录

一、CompletableFuture是什么

二、CompletableFuture用法

2.1、创建CompletableFuture

2.1.1、直接创建

2.1.2、创建一个使用指定数据作为结果的已结束的CompletableFuture

 2.1.3、通过执行异步任务获取CompletableFuture

 2.2、获取任务结果

2.3、消费结果

2.3.1、whenComplete

2.3.2、thenAccept

2.3.3、thenApply

2.3.4、thenRun

2.3.5、handle

2.3.6、exceptionally

2.4、多任务编排

2.4.1、 依赖(thenCompose)

2.4.2、 AND(thenCombine,thenAcceptBoth,runAfterBoth)

2.4.3、OR(applyToEither)

2.4.4、 并行(allOf,anyOf)


一、CompletableFuture是什么

CompletableFuture是对Future的扩展和增强。CompletableFuture实现了Future接口和CompletionStage使其实现了对任务编排的能力。借助这项能力,可以轻松地组织不同任务的运行顺序、规则以及方式。

二、CompletableFuture用法

2.1、创建CompletableFuture

2.1.1、直接创建

CompletableFuture completableFuture=new CompletableFuture();

2.1.2、创建一个使用指定数据作为结果的已结束的CompletableFuture

CompletableFuture<String> test1 = CompletableFuture.completedFuture("test");

 2.1.3、通过执行异步任务获取CompletableFuture

/**
 * 使用默认线程池执行异步任务,有返回值
 */
CompletableFuture.supplyAsync(() -> "hello CompletableFuture!");
/**
 * 使用指定线程池执行异步任务,有返回值
 */
CompletableFuture.supplyAsync(() -> "Hello CompletableFuture!", Executors.newCachedThreadPool());
/**
 * 使用默认线程池执行异步任务,无返回值
 */
CompletableFuture.runAsync(() -> System.out.println("Hello runAsync!"));
/**
  * 使用指定线程池执行异步任务,无返回值
  */
CompletableFuture.runAsync(() -> System.out.println("Hello RunAsync!"),  Executors.newCachedThreadPool());

 2.2、获取任务结果

方法是否阻塞是否抛出检查异常说明
get()阻塞抛出检查异常
getNow(V value)不阻塞不抛出如果任务没有结束就返回指定的默认值
get(long timeout, TimeUnit unit)阻塞指定时间抛出
join()阻塞不抛出

示例代码: 

        /**
         * 获取任务结果,阻塞直到任务结束,会抛出检查异常
         */
        String test = CompletableFuture.supplyAsync(() -> "Hello").get();
        /**
         * 获取任务结果,如果超过等待之间任务未结束则抛出TimeoutException
         */
        test = CompletableFuture.supplyAsync(() -> "test").get(10, TimeUnit.MILLISECONDS);
        /**
         * 如果任务结束则返回任务结果,如果任务未结束则返回指定的默认值
         */
        test = CompletableFuture.supplyAsync(() -> "test").getNow("default");

        /**
         * 阻塞获取任务结果,和get相似,但是不会抛出检查异常
         */
        test = CompletableFuture.supplyAsync(() -> "join").join();

2.3、消费结果

2.3.1、whenComplete

whenComplete是当某个任务执行完成后执行的回调方法,不管任务异常还是正常结束都会执行该回调;该回调的入参是任务的执行结果和异常;
如果是正常执行则异常为null,回调方法对应的CompletableFuture的result和该任务一致,如果该任务正常执行,则get方法返回执行结果,如果是执行异常,则get方法抛出异常。

方法说明
 whenComplete(BiConsumer<? super T, ? super Throwable> action )在当前线程中同步执行回调操作
 whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action )在默认线程池中异步执行回调
 whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action,Executor executor )在指定线程池中异步执行回调

 示例代码如下:

 CompletableFuture.supplyAsync(() -> {
            System.out.println("threadId: " + Thread.currentThread().getId() + ",threadName: " + Thread.currentThread().getName());
            return "whenComplete";
        }).whenComplete((a, e) ->
                System.out.println("threadId: " + Thread.currentThread().getId() + ",threadName: " + Thread.currentThread().getName() + ", a: " + a)
        );

CompletableFuture.supplyAsync(()->{throw new RuntimeException("");}).whenComplete((a,e)->System.out.println(e));

执行结果如下:

threadId: 11,threadName: ForkJoinPool.commonPool-worker-9
threadId: 1,threadName: main, a: whenComplete
java.util.concurrent.CompletionException: java.lang.RuntimeException: 

2.3.2、thenAccept

thenAccept只消费正常处理结束的结果,不消费异常同时没有返回值

方法说明
 thenAccept(Consumer<? super T> action )在当前线程中消费同步消费
thenAcceptAsync(Consumer<? super T> action )在默认线程池中异步消费
thenAcceptAsync(Consumer<? super T> action,
    Executor executor )
在指定线程池中异步消费
CompletableFuture.supplyAsync(() -> "thenAccept")
                .thenAccept(str -> System.out.println("threadId: " + Thread.currentThread().getId() + ",threadName: " + Thread.currentThread().getName()+",str="+str));
        CompletableFuture.supplyAsync(() -> "thenAcceptAsync")
                .thenAcceptAsync(str -> System.out.println("threadId: " + Thread.currentThread().getId() + ",threadName: " + Thread.currentThread().getName()+",str="+str));
        CompletableFuture.supplyAsync(()->"thenAcceptAsync")
                .thenAcceptAsync(str-> System.out.println("threadId: " + Thread.currentThread().getId() + ",threadName: " + Thread.currentThread().getName()+",str="+str),Executors.newSingleThreadExecutor());

执行结果如下:

threadId: 1,threadName: main,str=thenAccept
threadId: 11,threadName: ForkJoinPool.commonPool-worker-9,str=thenAcceptAsync
threadId: 16,threadName: pool-6-thread-1,str=thenAcceptAsync

2.3.3、thenApply

thenApply和thenAccept的相同点都是消费任务正常结束的结果,不同点就是thenAccept没有返回值而thenApply有返回值。

CompletableFuture.supplyAsync(() -> "Dora")
                .thenApply(str ->"Hello, "+str).thenAccept(System.out::println);
CompletableFuture.supplyAsync(() -> "Dora")
                .thenApplyAsync(str ->"Hello, "+str).thenAccept(System.out::println);
CompletableFuture.supplyAsync(()->"Dora")
                .thenApplyAsync(str ->"Hello, "+str).thenAccept(System.out::println);

执行结果如下:

Hello, Dora
Hello, Dora
Hello, Dora 

2.3.4、thenRun

thenRun和thenAccept相似,都是在任务正常结束后执行且都没有返回值,两者的区别是thenAccept关心上一个任务的结果而thenRun不关心结果。

CompletableFuture.supplyAsync(() -> "thenRun")
                .thenRun(() -> System.out.println("threadId: " + Thread.currentThread().getId() + ",threadName: " + Thread.currentThread().getName()));
CompletableFuture.supplyAsync(() -> "thenRunAsync")
                .thenRunAsync(() -> System.out.println("threadId: " + Thread.currentThread().getId() + ",threadName: " + Thread.currentThread().getName()));
CompletableFuture.supplyAsync(()->"thenRunAsync")
                .thenRunAsync(()-> System.out.println("threadId: " + Thread.currentThread().getId() + ",threadName: " + Thread.currentThread().getName()),Executors.newSingleThreadExecutor());

2.3.5、handle

    handle方法的使用和whenComplete类似

handlewhenComplete
入参任务的结果和异常任务的结果和异常
触发阶段任务结束后,不管正常结束还是异常结束任务结束后,不管正常结束还是异常结束
返回值有返回值Void

2.3.6、exceptionally

exceptionally是当任务执行出现异常时的回调处理,否则不会触发该回调;可以使用whenComplete和handle方法替代该方法

//如果任务执行异常则返回"exception"
CompletableFuture.supplyAsync(()->{throw new RuntimeException("");}).exceptionally((e->"exception")).whenComplete((a,e)->System.out.println(a+" "+e));

执行结果如下:

exception null

2.4、多任务编排

2.4.1、 依赖(thenCompose)

 thenCompose 是依赖前一个任务结果,前一个任务的结果作为当前任务的入参

CompletableFuture.supplyAsync(() -> "hello").thenCompose(p -> CompletableFuture.supplyAsync(() -> p + " world")).thenAccept(System.out::println);

2.4.2、 AND(thenCombine,thenAcceptBoth,runAfterBoth)

thenCombine 是将两个任务的结果进行合并处理

String test = CompletableFuture.supplyAsync(() -> {

            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "a";
        }).thenCombineAsync(CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (Exception e) {

            }
            return "b";
        }), (a, b) -> a + "_" + b).join();

结果是:

a_b 

thenAcceptBoth和thenCombine比较类似,区别是thenCombine是有返回值,而thenAcceptBoth是消费前两个任务的结果没有返回值

 CompletableFuture.supplyAsync(() -> "hello").thenAcceptBoth(CompletableFuture.supplyAsync(() -> "world"), (a, b) -> {
            System.out.println(a + "—" + b);
        });

 结果是:

a-b

runAfterBoth和thenCombine、thenAcceptBoth有所不同,它不关心前两个任务的结果,只要前两个任务都结束就会触发第三个任务执行

CompletableFuture.supplyAsync(() -> "hello").runAfterBoth(CompletableFuture.supplyAsync(() -> "world"), () -> {
            System.out.println("end");
        });

结果是

end

2.4.3、OR(applyToEither)

applyToEither从名字上就可以知道两个任务是或的关系,只要有一个任务结束就出发第三个任务执行。

CompletableFuture.supplyAsync(() -> "first").applyToEither(CompletableFuture.supplyAsync(() -> "second"), str ->
             str + " end").thenAccept(System.out::println);

结果是:

first end 

acceptEither是只要有一个任务结束第三个任务就消费它

CompletableFuture.supplyAsync(() -> "first").acceptEither(CompletableFuture.supplyAsync(() -> "second"), str ->System.out.println(str+" end"));

 

2.4.4、 并行(allOf,anyOf)

          allOf 是所有任务都必须执行结束,anyOf是有一个任务正常结束即可。
 

CompletableFuture.allOf(CompletableFuture.supplyAsync(()->"a"),CompletableFuture.supplyAsync(()->"b")).join();

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

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

相关文章

云原生技术中台 CNStack2.0 正式发布

作者&#xff1a;奥陌 11 月 5 日&#xff0c;在 2022 杭州 云栖大会上&#xff0c;云原生技术中台 CNStack2.0 正式发布。 阿里巴巴资深技术专家 谢吉宝介绍 CNStack2.0 企业在数字化转型的过程中&#xff0c;一部分问题得到了解决&#xff0c;但随着 IT 水平的不断提升&am…

【Milvus的人脸检索】

0. 介绍 在上一篇文章中&#xff0c;介绍了milvus提供的以图搜图的样例&#xff0c;这篇文章就在以图搜图样例的基础上进行修改&#xff0c;实现人脸检索。 常见的人脸任务&#xff0c;分为人脸检测、人脸识别、人脸对比和人脸检索&#xff0c;其中人脸检索的含义是&#xff…

点成分享 | 蛋白质浓度测定之考马斯亮蓝(Bradford)法

蛋白质是组成生物细胞、组织的重要成分&#xff0c;生物的所有生命活动都离不开蛋白质的参与。蛋白质是生命的物质基础&#xff0c;是构成细胞的基本有机物&#xff0c;是生命活动的主要承担者。生物材料中蛋白质含量的测定是生物学研究中最重要也是最基本的实验操作之一&#…

【微机接口】串行通信基础

计算机通信:CPU与外部的信息交换 并行通信&#xff1a;数据所有位同时被传输 串行通信&#xff1a;数据被逐位顺序传送 串行通信类型&#xff1a; 串行异步通信&#xff1a;一个字符用起始位和停止位来完成收发同步。 串行同步通信&#xff1a;采用同步字符来完成收发双方同…

营丘福稻品牌山东大米 国稻种芯·中国水稻节:淄博高青招牌

营丘福稻品牌山东大米 国稻种芯中国水稻节&#xff1a;淄博高青招牌 淄博市广播电视台新生活 大众网海报新闻记者 董玉歌 淄博报道) 新闻中国采编网 中国新闻采编网 谋定研究中国智库网 中国农民丰收节国际贸易促进会 国稻种芯中国水稻节 中国三农智库网-功能性农业农业大健…

【电源专题】案例:电源芯片规格书大标题写5A那是能输出5A吗?

这个案例是找到了问题点后再去审查规格书发现规格书里竟然有写明!只是最初始不是我导入的芯片就是了(其实就算是我导入的,以前也没有测试方法和手段能发现异常),而且这个芯片已经用了好久好久了,现在都停产了,买不到了。 从下图所示的规格书大标题中可以看到同步升压芯片…

苹果Mac电脑L2TP连接公司内部网络失败解决方案

苹果Mac电脑L2TP连接公司内部网络 苹果Mac系统在创建VPN连接时&#xff0c;一直提示&#xff1a;L2TP-VPN服务器没有响应。请尝试重新连接。如果仍然有问题&#xff0c;请验证你的设置并与管理员联系。 我们在添加VPN的时候需要填写机器认证中的共享秘钥&#xff0c;我这里填…

详解容灾恢复过程中跨数据中心级的关键故障切换

【摘要】容灾设计过程当中需要考虑的故障切换的场景有很多,数据中心内部的高可用切换不在本次讨论范围之内,我们讨论的是容灾恢复过程中的关键跨数据中心级的故障切换场景,从网络层到存储层都会涉及到。(文中涉及相关技术产品参数请以官网最新发布为准) 1. 容灾设计需要进…

c++异常处理

目录 1.c异常的由来 2.怎么使用异常来解决问题 3.异常安全 4.异常规范 5.异常处理的优缺点 1.c异常的由来 在c语言中&#xff0c;如果程序出现了错误&#xff0c;采用的是返回错误码的方式。最常见的&#xff1a; int main() {return 0; } 这里的return 0的0就是表示返…

Kubernetes学习(一)入门及集群搭建

一、简介 1.简介 Kubernetes 最初源于谷歌内部的Borg&#xff0c;Kubernetes 是一个全新的基于容器技术的分布式架构解决方案。 包含几个基本功能&#xff1a; 1.将应用水平扩容到多个集群 2.为扩容的实例提供负载均衡策略 3.提供基本的健康检查和自愈能力 4.实现任务的…

电机无位置控制方法研究

无位置控制方法研究 1.无位置控制技术研究现状 2.反电动势过零检测法 3.反电动势三次谐波积分检测法 4.续流二极管法 5.磁链法 6.扩展卡尔曼滤波算法&#xff08;EKF&#xff09; 7.基于扩展卡尔曼滤波算法&#xff08;EKF&#xff09;的转速及位置估算 8.电感测量法 9.涡流效…

LeetCode-878. 第 N 个神奇数字【数学,二分查找,找规律】

LeetCode-878. 第 N 个神奇数字【数学&#xff0c;二分查找&#xff0c;找规律】 题目描述&#xff1a;解题思路一&#xff1a;二分答案容斥原理。给定一个上下界&#xff0c;然后依次增大下界或者减小上界&#xff0c;直到只剩一个答案。容斥原理是&#xff0c;加上两个集合&a…

六、TCP实现聊天

客户端&#xff1a; 连接服务器 Socket(address,port)发送消息 import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets;/*** 客…

LabVIEW使用VI Snippets存储和共享重用代码段

LabVIEW使用VI Snippets存储和共享重用代码段 VI Snippets是存储、共享和重用LabVIEW代码小部分的新方式。VI代码段将截图的可移植性与VI文件的功能结合在标准PNG图像中嵌入LabVIEW代码。当将VI代码段PNG图像拖到框图上时&#xff0c;它会将代码片段作为图形代码拖放&#xff…

【C++】重载运算符+-=>/*[]==++-- MyString 智能指针(* ->)

目录 15.重载运算符 15.1 eg.Person 15.2 eg.MyString 15.3 智能指针 15.重载运算符 定义&#xff1a;给原有的运算符赋予新的意义。 为什么重载<<或>>一定要用友元&#xff1f; 如果是重载双目操作符&#xff08;即为类的成员函数&#xff09;&#xff0c;就…

10年老码农亲授:什么是分布式系统

首先&#xff0c;分布式系统是在硬件成本日益提高&#xff0c;或者单机提升的成本过于昂贵而程序的问题得不到解决时&#xff0c;为了解决更加高效、内容量更大的数据而采取的一种解决手段。 而分布式系统又分为两个部分&#xff0c;计算和存储&#xff0c;而准确来说这两部分…

知行之桥EDI系统2022版Tomcat部署

1.首先需要下载Tomcat&#xff0c;可在Tomcat官网获取&#xff0c;本部署步骤以apache-tomcat-9.0.67.tar.gz为例&#xff0c;通过XFTP将该包放在服务器上的指定位置&#xff0c;如/opt/test 进入/opt/test文件夹后&#xff0c;在命令行执行以下命令对该包进行解压缩 tar -zxv…

大数据毕设 - 公交数据分析与可视化系统(大数据 python flask)

文章目录0 前言1 课题背景2 具体实现3 Flask框架4 ECharts可视化工具5 最后0 前言 &#x1f525; Hi&#xff0c;大家好&#xff0c;这里是丹成学长的毕设系列文章&#xff01; &#x1f525; 对毕设有任何疑问都可以问学长哦! 这两年开始&#xff0c;各个学校对毕设的要求越…

Smart Tomcat + Servlet API的应用

文章目录前言一、Smart Tomcat二、Servlet API1.HttpServlet&#xff08;1&#xff09;方法&#xff08;2&#xff09;描述servlet的生命周期&#xff08;3&#xff09;案例2.HttpServletRequest&#xff08;1&#xff09;方法&#xff08;2&#xff09;代码示例打印请求信息获…

若依框架图片上传、富文本框编辑器功能

文章目录一、前言二、效果三、编码过程1.前端&#xff1a;index.vueprojectShow.js富文本框: Editor/index.vue图片上传&#xff1a;ImgUploadCropper/index.vue2.后端&#xff1a;实体ProjectShowProjectShowControllerIProjectShowServiceProjectShowServiceImplProjectShowM…