JUC并发编程之CompletableFuture

news/2024/4/24 19:47:15/

Future

future是java5新加的一个接口,他提供了一种异步并行计算的功能

接口定义了操作异步任务执行的一些方法,如获取异步任务的执行结果、取消任务的执行、判断任务是否被取消、判断任务是否执行完毕

目的:异步多线程执行且有返回结果,特点:多线程/有返回/异步任务

补充:Runnable实现的是run方法,没有返回值,没有异常,Callable实现的是call方法,有返回值,需要处理异常

Future接口常用实现类Future Task异步任务

代码实现

public class CompletableFutureDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {FutureTask<String> futureTask = new FutureTask<>(new MyThread());Thread t1 = new Thread(futureTask,"t1");t1.start();System.out.println(futureTask.get());}
}class MyThread implements Callable<String>{@Overridepublic String call() throws Exception {System.out.println("----come in call()");return "hello Callable";}
}

 

future的优缺点

NO: 1、get方法容易阻塞:一旦调用,如果计算没有完成,容易程序阻塞

2、isDone轮询:轮询的方式会耗费CPU资源,而且也不见得能及时得到计算结果

小结:future对于结果的获取不是很友好,只能通过阻塞或轮询的方式得到任务结果

注:实际程序中轮询的方式并不比阻塞好,这么写是给用户看的,用户不可能看你的程序就停在那了,这么写可以给个提示,也不会直接异常

CompletableFuture的异步优化思路

背景:对于简单的业务场景使用Future完全OK,但是对于复杂的业务场景,比如:

1、回调通知:应对Future的完成时间,完成了可以告诉我,也就是我们的回调通知,通过轮询的方式去判断任务是否完成这样非常的占用CPU并且代码也不优雅

2、创建异步任务:Future+线程池配合

3、多个任务前后依赖可以组合处理:想将多个异步任务的计算结果组合起来,后一个异步任务的计算结果需要前一个异步任务结果的值,将两个或多个异步计算合成一个异步计算,这几个异步计算相互独立,同时后面这个又依赖前一个处理的结果

4、对计算速度最快:当Future集合中某个任务最快结束时,返回结果,返回第一名处理结果

CompletableFuture提供了一种观察者模式类似的机制,可以让任务完成后通知监听的一方

类架构说明

 

接口CompletionStage

1、CompletionStage代表异步计算过程中某一个阶段,一个阶段完成以后可能会触发另外一个阶段

2、一个阶段的执行可以是一个Function,Consumer或者Runnable

3、一个阶段的执行可能是被单个阶段的完成触发,也可能是由多个阶段一起触发

代表异步计算过程中的某一个阶段,一个阶段完成以后可能会触发另外一个阶段

类CompletableFuture

1、在java8当中,CompletableFuture提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性,并且提供了函数式编程的能力,可以通过回调的方式处理计算结果,也提供了转换和组合ComplttableFuture的方法

2、他可能代表一个明确完成的Future,也有可能代表一个完成阶段,它支持在计算完成以后触发一些函数或执行某个动作

3、它实现了Future和CompletionStage接口

注:从java8开始引入了CompletableFuture,他是Future的功能增强版,减少阻塞和轮询,可以传入回调对象,当异步任务完成或者发生异常时,自动调用回调对象的回调方法

优点:

1、异步任务结束时,会自动回调某个对象的方法

2、主线程设置好回调后,不再关心异步任务的执行,异步任务之间可以顺序执行

3、异步任务出错时,会自动回调某个对象的方法

函数式接口复习  

 CompletableFuture常用方法

1、获得结果和触发计算

public class CompletableFutureAPIDemo {public static void main(String[] args) {CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}return "abc";});//System.out.println(completableFuture.get());   阻塞主线程获取结果//System.out.println(completableFuture.get(2L,TimeUnit.SECONDS)); 等待指定时间获取结果//System.out.println(completableFuture.join());  阻塞线程获取结果System.out.println(completableFuture.getNow("xxx")); //立即获取结果不阻塞,如果没计算完成返回XXXSystem.out.println(completableFuture.complete("completeValue")+"\t"+completableFuture.join());//是否打断get方法立刻获得括号值}
}

2、对计算结果进行处理

public class CompletableFutureAPI2Demo {public static void main(String[] args) {ExecutorService threadPool = Executors.newFixedThreadPool(3);//thenApply//计算结果存在依赖关系,这两个线程串行化//异常相关:由于存在依赖关系(当前步错,不走下一步),当前步骤有异常的话就叫停//handle:区别:有异常也可以往下一步走,根据带的异常参数可以进一步处理CompletableFuture.supplyAsync(() -> {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("111");return 1;},threadPool).handle((f,e) -> {int i = 10/0;System.out.println("222");return f+2;}).thenApply(f -> {System.out.println("333");return f+3;}).whenComplete((v,e) -> {if (e == null){System.out.println("------计算结果:"+v);}}).exceptionally(e -> {e.printStackTrace();System.out.println("e = " + e.getMessage());return null;});threadPool.shutdown();System.out.println(Thread.currentThread().getName()+"-----主线程先去忙其他任务");}
}

3、对计算结果进行消费

//接受任务的处理结果,并消费处理,无返回结果
public class CompletableFutureAPI3Demo {public static void main(String[] args) {
//        CompletableFuture.supplyAsync(() -> {
//            return 1;
//        }).thenApply(f -> {
//            return f+2;
//        }).thenApply(f -> {
//            return f+3;
//        }).thenAccept(System.out::println);//任务之间的顺序执行/*** 1、thenRun:任务A执行完执行任务B,并且B不需要A的结果* 2、thenAccept:任务  A执行完执行B,B需要A的结果,但是任务B无返回值* 3、thenApply:任务A执行完执行B,B需要A的结果,同时任务B有返回值*/System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenRun(() -> {}).join());System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenAccept(r-> System.out.println("r = " + r)).join());System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenApply(r -> r+"ResuleB").join());}
}

4、对计算速度进行选用

public class CompletableFutureFastDemo {public static void main(String[] args) {CompletableFuture<String> playA = CompletableFuture.supplyAsync(() -> {System.out.println("A come in");try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}return "playA";});CompletableFuture<String> playB = CompletableFuture.supplyAsync(() -> {System.out.println("B come in");try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}return "playB";});CompletableFuture<String> result = playA.applyToEither(playB, f -> f  + " is winer");System.out.println(Thread.currentThread().getName()+"\t"+"--------"+result.join());}
}

5、对计算结果进行合并

public class CompletableFutureCombineDemo {public static void main(String[] args) {CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName() + "\t ---启动");try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}return 10;});CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName() + "\t ---启动");try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}return 20;});CompletableFuture<Integer> result = completableFuture1.thenCombine(completableFuture2, (x, y) -> {System.out.println("开始两个结果合并:" + x + y);return x + y;});System.out.println("result.join() = " + result.join());}
}

注:CompletableFuture线程池运行选择

1、没有传入自定义线程池,都用默认线程池ForkJoinPool

2、传入了一个自定义线程池

如果你执行第一个任务的时候,传入了一个自定义线程池

调用thenRun方法执行第二个任务时,第二个任务和第一个任务使用的是同一个线程池

调用thenRunAsync方法执行第二个任务时,则第一个任务使用的是你自己传入的线程池,第二个任务使用的是ForkJoin线程池

备注:

有可能处理太快,系统优化切换原则,直接使用main线程处理

public class CompletableFutureWithThreadPoolDemo {public static void main(String[] args) {ExecutorService threadPool = Executors.newFixedThreadPool(5);try {CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(() -> {try {TimeUnit.MILLISECONDS.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("1号任务" + "\t" + Thread.currentThread().getName());return "abcd";},threadPool).thenRunAsync(() -> {try {TimeUnit.MILLISECONDS.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("2号任务" + "\t" + Thread.currentThread().getName());}).thenRun(() -> {try {TimeUnit.MILLISECONDS.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("3号任务" + "\t" + Thread.currentThread().getName());}).thenRun(() -> {try {TimeUnit.MILLISECONDS.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("4号任务" + "\t" + Thread.currentThread().getName());});System.out.println(completableFuture.get(2L, TimeUnit.SECONDS));} catch (Exception e) {e.printStackTrace();}finally {threadPool.shutdown();}}
}


http://www.ppmy.cn/news/48278.html

相关文章

腾讯云轻量级云服务器Centos7防火墙开放8080端口

腾讯云轻量级云服务器Centos7防火墙开放8080端口 一、centos7防火墙打开端口 因为Centos7以上用firewalld代替了iptables,也就是说firewalld开通了8080端口应该就行了 1.查看8080是否已经放开 sudo firewall-cmd --permanent --zonepublic --list-ports2.查看防火墙状态 s…

ETCD(四)读请求处理过程

客户端通过etcdctl执行get命令 etcdctl get name --endpoints localhost:12379,192.158.00.32:12379client端 首先是client会解析这条命令&#xff0c;包括其中的get API方法&#xff0c;key值&#xff0c;请求server地址。解析完之后etcdctl会创建一个clientv3库对象&#xf…

基于C++开发的医院医学影像PACS 可二次开发,三维重建

医学影像PACS系统源码&#xff0c;集成三维影像后处理功能&#xff0c;包括三维多平面重建、三维容积重建、三维表面重建、三维虚拟内窥镜、最大/小密度投影、心脏动脉钙化分析等功能。系统功能强大&#xff0c;代码完整。有演示。 本套PACS系统专门针对医院工作流程设计的&am…

Redis---主从复制

一、redis主从复制 主从复制&#xff1a;是存储数据的服务结构 主服务器&#xff1a;接受客户端连接的服务器 从服务器&#xff1a;自动与主服务器保持数据一致的服务器 配置主从复制 1、环境准备 主服务器 主机名&#xff1a;master IP地址&#xff1a;192.168.11.101/…

企业想注销境外投资备案应该怎么做?

我们今天就来说一下关于境外投资备案的注销&#xff0c;有办理的需求&#xff0c;当然就有注销的需求。如果您当初想去海外投资并购一家公司&#xff0c;因此办理了境外投资备案&#xff0c;但是由于种种原因可能没有办法投资下去了&#xff0c;那么这个时候我们就需要做境外投…

git服务器搭建

ubuntu搭建git服务器 安装git&#xff1a;apt install git建立用户账户&#xff1a;用来存放git远程仓库&#xff0c;这里只是个ubuntu账户&#xff0c;没有特殊含义&#xff1b; adduser gitServer 设置账户密码&#xff1a; passwd gitServer 创建仓库目录&#xff1a;该目录…

代码随想录算法训练营第三十八天|理论基础、509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

文章目录 理论基础509. 斐波那契数70. 爬楼梯746. 使用最小花费爬楼梯 理论基础 动态规划-DP 动态规划中每一个状态一定是由上一个状态推导出来的&#xff0c;这一点就区分于贪心&#xff0c;贪心没有状态推导&#xff0c;而是从局部直接选最优的 背包问题&#xff1a; 动态规…

Progress ThemeBuilder crack

Progress ThemeBuilder crack 自定义输入将覆盖自定义日期输入和下拉列表。 Fluent主题中的图表不应用系列颜色。 撤消重做操作会导致重复以前编辑过的变量。 拆分器折叠的拆分条模板错误。 ThemeBuilder是一个多功能工具&#xff0c;可以帮助您创建视觉样式&#xff0c;并将其…

Redis缓存MySQL数据库存储二者如何保证数据一致性

文章目录 Redis缓存MySQL数据库存储二者如何保证数据一致性数据一致性问题缓存穿透缓存雪崩 Redis缓存MySQL数据库存储一致性解决方案方案一&#xff1a;读写数据库时同步更新缓存方案二&#xff1a;使用消息队列异步更新缓存 总结 Redis缓存MySQL数据库存储二者如何保证数据一…

背锅侠?软件测试各类bug分类定位,从功能到性能超细总结......

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 遇到功能性问题&a…

软件测试概念篇(下)|开发模型与测试模型

作者&#xff1a;爱塔居 专栏&#xff1a;软件测试 作者简介&#xff1a;大三学生&#xff0c;希望同大家一起进步&#xff01; 文章简介&#xff1a;主要介绍软件生命周期、瀑布模型和螺旋模型两个开发模型&#xff0c;V模型和W模型两个测试模型 文章目录 目录 文章目录 一、软…

IOC容器与DI依赖注入示例

IOC容器与DI依赖注入示例 IOC深入理解IOC示例&#xff1a; DI深入理解DI示例 IOC深入理解 我们先通过几个问题来加深一下对IOC的理解 (1)Spring是使用IOC容器来管理bean对象的&#xff0c;我们主要管理什么? 主要管理项目中所使用到的类对象&#xff0c;比如(Service层对像和…

在现成的3D打印机上进行实验理论:一种数据孪生的攻击探测框架

在现成的3D打印机上提供了一种DT中攻击探测框架的DT解决方案的实验演示&#xff0c;作为说明性CPMS资源。通过网络安全DT对打印机正常运行、异常运行和攻击三种情况下的实验数据进行收集和分析&#xff0c;得出攻击检测结果。实验装置概述如下图所示。该实验研究是在现实世界设…

tokenURI的实现方式

做数字藏品最重要的function是tokenURI(tokenId)。 实现1 基本路径tokenID ERC721 function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {_requireMinted(tokenId);string memory baseURI _baseURI();return bytes(baseURI).length &…

HarmonyOS原子化服务卡片整改、下架、升级失败部分原因及处理办法

随着HarmonyOS应用体系相关规则、团队的不断发展和完善&#xff0c;早期上架运营的HarmonyOS原子化服务卡片&#xff0c;很多都收到了整改、下架的通知&#xff0c;主要集中在用户协议、隐私声明、服务卡片的设计规范性等细节方面的问题&#xff1b;需要进行优化调整升级才行。…

源码:LeakCanary

一、介绍 自动检测内存泄漏的检查工具 二、使用 debugImplementation com.squareup.leakcanary:leakcanary-android:2.5debugImplementation只在debug模式的编译和最终的debug apk打包时有效 Memory Profiler 使用步骤 生成的内存泄漏快照 会放在sdcard/Download/leakcanar…

SSR在天猫优品大促会场的探索实践

BBC 发现其网站加载时间每增加一秒&#xff0c;用户便会流失 10%。为提高页面的秒开率&#xff0c;我们不断探索着优化策略&#xff0c;仅仅在浏览器领域下的优化已经满足不了我们的极致要求&#xff0c;开始往服务端方向不断探索。本文将讨论业务接入SSR的几个问题&#xff1a…

Spring Security --- formLogin配置

目录 环境准备 配置自定义登录表单页面 配置登录成功的跳转页面方式 配置登录失败的跳转页面方式 前端表单参数获取 CustomWebSecurityConfigurerAdapter配置类代码示例 环境准备 创建springboot项目引入spring security框架引入thymeleaf模板引擎 配置自定义登录表单页面…

水平居中、垂直居中的几种方法

水平居中的方法&#xff1a; 若是针对inline, 内联块inline-block, 内联表inline-table, inline-flex元素及img,span,button等元素 父元素设置 text-align:center; 绝对定位&#xff1b;弹性布局&#xff1b;grid网格布局 不定宽块状元素 设置 margin&#xff1a;auto; 绝对定…

第二章:uniapp整合axios之真机测试两问题

第二章&#xff1a;uniapp整合axios之真机测试两问题 上一章节&#xff0c;笔者编写了uniapp整合axios并实现前后端跨域请求的方案&#xff0c;完成了这些基本配置后&#xff0c;在浏览器端的测试基本是可以完成了&#xff0c;但是当笔者将程序运行到手机时&#xff0c;却出现…