CompletableFuture使用

一、核心API

  • 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)

没有指定Executor的方法,直接使用默认的ForkJoinPool.commonPool() 作为它的线程池执行异步代码。

如果指定线程池,则使用我们自定义的或者特别指定的线程池执行异步代码

线程池可以参考

CPU 密集型运算

通常采用 cpu 核数 + 1 能够实现最优的 CPU 利用率,+1 是保证当线程由于页缺失故障(操作系统)或其它原因导致暂停时,额外的这个线程就能顶上去,保证 CPU 时钟周期不被浪费。

I/O 密集型运算

CPU 不总是处于繁忙状态,例如,当你执行业务计算时,这时候会使用 CPU 资源,但当你执行 I/O 操作时、远程RPC 调用时,包括进行数据库操作时,这时候 CPU 就闲下来了,你可以利用多线程提高它的利用率。

经验公式如下

线程数 = 核数 * 期望 CPU 利用率 * 总时间(CPU计算时间+等待时间) / CPU 计算时间。

 无返回值 使用

    public static void main(String[] args) throws ExecutionException, InterruptedException{CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {System.out.println(Thread.currentThread().getName()+"\t"+"-----come in");//暂停几秒钟线程try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {e.printStackTrace(); }System.out.println("-----task over");});System.out.println(future.get());}

有返回值

public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName()+"\t"+"-----come in");//暂停几秒钟线程try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }System.out.println("-----task over");return 1;});System.out.println(future.get());}

二、CompletableFuture常用方法

1、获得结果和触发计算

  • public T get()             主线程阻塞的等待返回结果。
  • public T get(long timeout, TimeUnit unit)   带超时时间主线程阻塞的等待返回结果。
  • public T getNow(T valueIfAbsent)   没有计算完成的情况下,返回一个默认结果
    public static void main(String[] args) throws ExecutionException, InterruptedException{CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }return 1;});//计算没有完成,返回0,计算完成,返回计算结果try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(completableFuture.getNow(0));}
  • public T join()   完成后返回结果值
    public static void main(String[] args) throws ExecutionException, InterruptedException{System.out.println(CompletableFuture.supplyAsync(() -> "hello").thenApply(r -> r + " world").join());}
  • public boolean complete(T value)   如果尚未完成,将返回的值get()种相关方法为给定值
    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException{CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }return 1;});//注释掉暂停线程,get还没有算完只能返回complete方法设置的444;暂停2秒钟线程,异步线程能够计算完成返回get
//        try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }//当调用CompletableFuture.get()被阻塞的时候,complete方法就是结束阻塞并get()获取设置的complete里面的值.System.out.println(completableFuture.complete(0)+"\t"+completableFuture.get());}

2、对计算结果进行处理 

  • public boolean thenApply(T value)   
    public static void main(String[] args) throws ExecutionException, InterruptedException{ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 20, 1L, TimeUnit.SECONDS,new LinkedBlockingQueue<>(50), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());//当一个线程依赖另一个线程时用 thenApply 方法来把这两个线程串行化,CompletableFuture.supplyAsync(() -> {//暂停几秒钟线程try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }System.out.println("111");return 111;},threadPoolExecutor).thenApply(f -> {//int age = 10/0; // 异常情况:那步出错就停在那步。System.out.println("222");return f + 1;}).thenApply(f -> {System.out.println("333");return f + 1;}).whenCompleteAsync((v,e) -> {System.out.println("-----v: "+v);}).exceptionally(e -> {e.printStackTrace();return null;});threadPoolExecutor.shutdown();}
  • handle
    public static void main(String[] args) throws ExecutionException, InterruptedException{ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 20, 1L, TimeUnit.SECONDS,new LinkedBlockingQueue<>(50), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());//当一个线程依赖另一个线程时用 handle 方法来把这两个线程串行化,// 异常情况:有异常也可以往下一步走,根据带的异常参数可以进一步处理CompletableFuture.supplyAsync(() -> {//暂停几秒钟线程try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }System.out.println("111");return 111;},threadPoolExecutor).handle((f,e) -> {int age = 10/0;System.out.println("222");return f + 1;}).handle((f,e) -> {System.out.println("333");return f + 1;}).whenCompleteAsync((v,e) -> {System.out.println("*****v: "+v);}).exceptionally(e -> {e.printStackTrace();return null;});threadPoolExecutor.shutdown();}

whenComplete和whenCompleteAsync的区别:
whenComplete:是执行当前任务的线程执行继续执行whenComplete的任务。
whenCompleteAsync:是执行把whenCompleteAsync这个任务继续提交给线程池来进行执行。

3、对计算结果进行消费

  • thenAccept  接收任务的处理结果,并消费处理,无返回结果
    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {CompletableFuture.supplyAsync(() -> 1).thenApply(f -> f + 2).thenApply(f -> f + 3).thenApply(f -> f + 4).thenAccept(System.out::println);}

thenRun(Runnable runnable)   任务 A 执行完执行 B,并且 B 不需要 A 的结果

thenAccept(Consumer action) 任务 A 执行完执行 B,B 需要 A 的结果,但是任务 B 无返回值

thenApply(Function fn) 任务 A 执行完执行 B,B 需要 A 的结果,同时任务 B 有返回值

4、对计算速度进行选用

  • applyToEither
    public static void main(String[] args) throws ExecutionException, InterruptedException{CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName() + "\t" + "---come in ");//暂停几秒钟线程try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }return 10;});CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName() + "\t" + "---come in ");try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }return 20;});CompletableFuture<Integer> thenCombineResult = completableFuture1.applyToEither(completableFuture2,f -> {System.out.println(Thread.currentThread().getName() + "\t" + "---come in ");return f + 1;});System.out.println(Thread.currentThread().getName() + "\t" + thenCombineResult.get());}

5、对计算结果进行合并 

  • thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn)                  

两个CompletionStage任务都完成后,最终能把两个任务的结果一起交给thenCombine 来处理

    public static void main(String[] args) throws ExecutionException, InterruptedException{CompletableFuture<Integer> thenCombineResult = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName() + "\t" + "---come in 1");return 10;}).thenCombine(CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName() + "\t" + "---come in 2");return 20;}), (x,y) -> {System.out.println(Thread.currentThread().getName() + "\t" + "---come in 3");return x + y;}).thenCombine(CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName() + "\t" + "---come in 4");return 30;}),(a,b) -> {System.out.println(Thread.currentThread().getName() + "\t" + "---come in 5");return a + b;});System.out.println("-----主线程结束,END");System.out.println(thenCombineResult.get());}

三、使用实例

下面是java虚拟线程官方视频的一个使用示例,翻译后视频连接【通向Java21-02-Java虚拟线程】 https://www.bilibili.com/video/BV1Ju4y1Q788/?share_source=copy_web&vd_source=36048a8ec755b67c73e0b0233a43f92b

下面代码意思是确保用户已保存在数据库中。 然后取出购物车。然后循环用户选择的商品,计算总价。 然后调用支付服务,并记录交易ID。 通过所有这些信息,发送包含交易所有详细信息的电子邮件

2、使用Completablefutrue获取一组数据的详细信息

        List<Object> collect = list.stream().map(v ->CompletableFuture.supplyAsync(() -> userService.getById(v))).collect(Collectors.toList()).stream().map(CompletableFuture::join).collect(Collectors.toList());

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

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

相关文章

【智能家居】二、添加火灾检测模块(烟雾报警功能点)

可燃气体传感器 MQ-2 和 蜂鸣器 代码段 controlDevice.h&#xff08;设备控制&#xff09;smokeAlarm.c&#xff08;烟雾报警器&#xff09;buzzer.c&#xff08;蜂鸣器&#xff09;mainPro.c&#xff08;主函数&#xff09;运行结果 可燃气体传感器 MQ-2 和 蜂鸣器 代码段 …

Pycharm配置jupyter使用notebook详细指南(可换行conda环节)

本教程为事后记录&#xff0c;部分图片非实操图片。 详细记录了pycharm配置jupyter的方法&#xff0c;jupyter添加其他conda环境的方法&#xff0c;远程密码调用jupyter的方法&#xff0c;修改jupyter工作目录的方法。 文章目录 一、入门级配置1. Pycharm配置Conda自带的jupyt…

华为云cce负载配置时间同步

华为云cce将负载配置好之后&#xff0c;发现里面的时间与真实时间不同步&#xff0c;差了12小时&#xff0c;怎么办&#xff1f; 这时候就需要配置时间同步了。 华为云cce里面通过配置数据存储的路径来解决这个问题的&#xff0c;配置后&#xff0c;需要重启负载。 新建负载…

三、shell - 变量

目录 1、简介 1.1 变量的定义语法: 1.2 变量的定义需遵循的规则 1.3 变量的作用域 2、用户变量 2.1 定义变量 2.2 访问变量 2.3 变量的其他赋值方式 2.4 只读变量 2.5 删除变量 ​​​​​​​3、环境变量 ​​​​​​​3.1 常见的环境变量 ​​​​​​​3.2 自…

030 - STM32学习笔记 - ADC(四) 独立模式多通道DMA采集

030 - STM32学习笔记 - ADC&#xff08;四&#xff09; 独立模式多通道DMA采集 中断模式和DMA模式进行单通道模拟量采集&#xff0c;这节继续学习独立模式多通道DMA采集&#xff0c;使用到的引脚有之前使用的PC3&#xff08;电位器&#xff09;&#xff0c;PA4&#xff08;光敏…

【刷题笔记】串联所有单词的子串||暴力通过||滑动窗口

串联所有单词的子串 1 题目描述 https://leetcode.cn/problems/substring-with-concatenation-of-all-words/ 给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。 s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。 …

基于STC12C5A60S2系列1T 8051单片机的液晶显示器LCD1602显示整数、小数应用

基于STC12C5A60S2系列1T 8051单片机的液晶显示器LCD1602显示整数、小数应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍液晶显示器LCD1602简单介绍IIC通信简单介绍…

【每日一题】1657. 确定两个字符串是否接近-2023.11.30

题目&#xff1a; 1657. 确定两个字符串是否接近 如果可以使用以下操作从一个字符串得到另一个字符串&#xff0c;则认为两个字符串 接近 &#xff1a; 操作 1&#xff1a;交换任意两个 现有 字符。 例如&#xff0c;abcde -> aecdb操作 2&#xff1a;将一个 现有 字符的…

解决plot画图中文乱码问题(macbook上 family ‘sans-serif‘ not found)

一、matplotlib画图中文乱码问题 使用matplotlib.pyplot画图&#xff0c;有中文字体会显示乱码问题&#xff0c;这时需要添加如下代码&#xff1a; import matplotlib.pyplot as pltplt.rcParams["font.sans-serif"] ["SimHei"]二、macbook没有SimHei的…

分布式仿真SNN的思考

我之前实现的仿真完全基于如下图设计的 将整体的网络构成见一个邻接表&#xff0c;突触和神经元作为类分别存储&#xff0c;所以当一个神经元发射脉冲时&#xff0c;很容易的将脉冲传输到突触指向的后神经元。但是在分布式方丈中&#xff0c;由多个进程仿真整体的网络&#xff…

WPS导出的PDF比较糊,和原始的不太一样,将带有SVG的文档输出为PDF

一、在WPS的PPT中 你直接输出PDF可能会导致一些问题&#xff08;比如照片比原来糊&#xff09;/ 或者你复制PPT中的图片到AI中类似的操作&#xff0c;得到的照片比原来糊&#xff0c;所以应该选择打印-->高级打印 然后再另存为PDF 最后再使用AI打开PDF文件再复制到你想用…

基于单片机的排队叫号系统设计

1&#xff0e;设计任务 利用AT89C51单片机为核心控制元件,设计一个节日彩灯门&#xff0c;设计的系统实用性强、操作简单&#xff0c;实现了智能化、数字化。 基本要求&#xff1a;利用单片机AT89C51设计排队叫号机&#xff0c;能实现叫号功能。 创新&#xff1a;能显示叫号…

猫头虎分享ubuntu20.04下VSCode无法输入中文解决方法

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

【EasyExcel】导出excel并支持自定义设置数据行背景颜色等

需求背景&#xff1a; 根据查询条件将列表数据导出&#xff0c;并筛选出满足某个条件的数据&#xff0c;将满足条件的数据的背景颜色设置成黄色。 &#xff08;本文例子如&#xff1a;name出现的次数大于等于2&#xff0c;将相关数据背景颜色都设置为黄色&#xff09; …

算法通关村第一关—链表高频面试题(白银)

链表高频面试题 一、五种方法解决两个链表的第一个公共子节点的问题 面试 02.07.链表相交1.首先想到的是暴力解&#xff0c;将第一个链表中的每一个结点依次与第二个链表的进行比较&#xff0c;当出现相等的结点指针时&#xff0c;即为相交结点。虽然简单&#xff0c;但是时间…

常见智力题汇总

常见智力题汇总 扔瓶子问题扑克牌问题出队问题烧绳子问题赛马问题求出前三名求出前五名 接水问题种树问题硬币问题宝石问题核酸检测问题 笔者最近面试遇到了好几道智力题&#xff0c;这些题目特点就是如果没有见过&#xff0c;很难第一时间思考得到答案&#xff0c;因此笔者面试…

VUE2+THREE.JS项目搭建

THREE项目搭建 简介学习文档推荐搭建1.下载three.js2.新建3DWorkShop.vue文件3.创建utils/three/tool.js4.创建components/three/draw.vue[重点]4.1 引入文件4.2 初始化场景4.3 初始化渲染器4.4 初始化光源4.5 初始化相机(人眼模式)4.6 初始化控制器4.7 初始化动画4.8 添加全局…

功率信号源简介及其应用有哪些内容

功率信号源是一种能够提供稳定输出功率信号的设备或电路。它在许多领域中都有广泛的应用。以下是一些关于功率信号源的内容&#xff1a; 功率信号源简介&#xff1a;功率信号源是一种电子设备或电路&#xff0c;它能够提供稳定的输出功率信号。功率信号源通常由放大器、稳压器、…

rest_framework_django学习笔记一(序列化器)

rest_framework_django学习笔记一(序列化器) 一、引入Django Rest Framework 1、安装 pip install djangorestframework2、引入 INSTALLED_APPS [...rest_framework, ]3、原始RESTful接口写法 models.py from django.db import models 测试数据 仅供参考 INSERT INTO de…

力扣:1419. 数青蛙

题目&#xff1a; 代码&#xff1a; class Solution { public:int minNumberOfFrogs(string croakOfFrogs){string s "croak";int ns.size();//首先创建一个哈希表来标明每个元素出现的次数&#xff01;vector<int>hash(n); //不用真的创建一个hash表用一个数…