CompletableFuture详解

目录

介绍

Future介绍

CompletableFuture介绍

CompletableFuture常用的API介绍

常用的静态方法源码解析

runAsync

源码

案例

结果 

 supplyAsync

源码

案例

结果

规律

CompletableFuture获取返回值方法介绍

返回值区别

代码演示

返回结果 

CompletableFuture其他常用的API

thenApply

源码 

案例

结果

thenCompose

源码

案例

结果

thenAccept和thenRun 

源码

案例

结果

complete

源码

案例

结果

whenComplete

源码

案例

结果 

exceptionally 

源码

案例

结果

 whenComplete+exceptionally案例

结果

 handle

源码

案例

结果

 allof

源码

案例

结果

anyOf

源码

案例

结果

提示


介绍

Future介绍

了解CompletableFuture可以先了解Future,可以查看下面这篇文章

Callable、Future和FutrueTask详解-CSDN博客

CompletableFuture介绍

CompletableFuture是一个类,主要实现了Future和ComletionStage两个接口。因此,CompletableFuture包含了Futrure和CompletionStage的功能。

CompletableFuture常用的API介绍

官方推荐CompletableFutrue静态方法,所以我们先介绍它的静态方法

常用的静态方法源码解析

线程池工具类

线程池工具类_java线程池工具类-CSDN博客

runAsync

runAsync:无返回值,可以自定义线程池,如果没有自定义线程池,默认使用ForkJoinPool线程池

源码
// 默认线程池 
public static CompletableFuture<Void> runAsync(Runnable runnable) {return asyncRunStage(asyncPool, runnable);}
// 自定义线程池public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor) {return asyncRunStage(screenExecutor(executor), runnable);}
案例
public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture.runAsync(() -> {System.out.println(Thread.currentThread().getName() + "  -------执行异步任务,无返回值结果---------");});CompletableFuture.runAsync(() -> {System.out.println(Thread.currentThread().getName() + "  -----自定义线程执行异步任务,无返回结果------");}, ThreadPoolUtils.getThreadPool());}
结果 

ForkJoinPool.commonPool-worker-9  -------执行异步任务,无返回值结果---------
myPool-0  -----自定义线程执行异步任务,无返回结果------

 supplyAsync

supplyAsync:有返回值,可以自定义线程池,如果没有自定义线程池,默认使用ForkJoinPool线程池

源码
//默认线程池public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {return asyncSupplyStage(asyncPool, supplier);}
// 自定义线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor) {return asyncSupplyStage(screenExecutor(executor), supplier);}
案例
public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<String> completableFuture1 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName() + "  ------执行异步任务,有返回值------");return "返回值1";});System.out.println(completableFuture1.get());CompletableFuture<String>  completableFuture2 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName() + "  ------自定义线程池执行异步任务,有返回值------");return "返回值2";}, ThreadPoolUtils.getThreadPool());System.out.println(completableFuture2.get());}
结果

ForkJoinPool.commonPool-worker-9  ------执行异步任务,有返回值------
返回值1
myPool-0  ------自定义线程池执行异步任务,有返回值------
返回值2

规律

  • supply开头:可以返回异步执行的结果
  • run开头:不会返回结果,只是执行线程任务

CompletableFuture获取返回值方法介绍

  • join:返回结果或者抛出一个unchecked异常(CompletionException),不需要显式捕获异常
  • get:此方法继承Future的get阻塞方法,返回结果或者一个具体的异常(ExecutionException,InterruptedException)
  • getNow:如果当前任务执行完成,返回执行结果,否则返回默认值

返回值区别

  • join与get区别在于join()返回计算的结果或者抛出一个异常,而get会返回一个具体的异常
  • getNow与join和get的区别,getNow返回当前执行好的结果,如果当前未执行完,则返回设定好的默认值。

代码演示

public static void main(String[] args) {CompletableFuture completableFuture1 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName() + "  ------执行异步任务,有返回值------");return "返回值1";});try {System.out.println("get():" + completableFuture1.get());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}CompletableFuture completableFuture2 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName() + "  ------自定义线程池执行异步任务,有返回值------");return "返回值2";}, ThreadPoolUtils.getThreadPool());System.out.println("join():" + completableFuture2.join());CompletableFuture completableFuture3 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName() + "  ------自定义线程池执行异步任务,有返回值------");try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}return "返回值3";}, ThreadPoolUtils.getThreadPool());System.out.println("------这一步,直接返回默认值------");System.out.println("getNow():" + completableFuture3.getNow("默认值"));try {System.out.println("-----进行线程阻塞,等待completableFuture3内容执行完成-----");System.out.println("get():" + completableFuture3.get());} catch (ExecutionException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("-----当前异步任务已经执行完成,返回结果-----");System.out.println("getNow():" + completableFuture3.getNow("默认值"));}

返回结果 

ForkJoinPool.commonPool-worker-9  ------执行异步任务,有返回值------
get():返回值1
myPool-0  ------自定义线程池执行异步任务,有返回值------
join():返回值2
------这一步,直接返回默认值------
getNow():默认值
-----进行线程阻塞,等待completableFuture3内容执行完成-----
myPool-1  ------自定义线程池执行异步任务,有返回值------
get():返回值3
-----当前异步任务已经执行完成,返回结果-----
getNow():返回值3

CompletableFuture其他常用的API

thenApply

thenApply拿到上一步异步线程返回的结果进行后续处理。可以拿到上一次线程执行的返回结果,并且可以一直传递下去。

源码 
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn) {return uniApplyStage(null, fn);}
案例
public static void main(String[] args) {String str = "上海";String str2 = "深圳";CompletableFuture<StringBuffer> future = CompletableFuture.supplyAsync(() -> {return new StringBuffer("北京");// a是上一步异步线程返回的结果}, ThreadPoolUtils.getThreadPool()).thenApply(a -> a.append(str)).thenApply(b -> b.append(str2));try {System.out.println(future.get());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}
结果

北京上海深圳

thenCompose

thenCompose方法功能跟thenApply相似,都是会在上一个任务执行完成以后,拿到上一步的执行结果,进行后续处理,不同的是,两个方法的参数不一致,并且,thenCompose在执行的时候,需要创建一个新的CompletableFuture。

源码
  public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn) {return uniComposeStage(null, fn);}
案例
public static void main(String[] args) throws ExecutionException, InterruptedException {/*** supply直接返回,会得到一个CompletableFuture<String>* 经过thenApply处理,CompletableFuture<String>会转成一个CompletableFuture<Integer>* 但CompletableFuture是同一个*/CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {// 返回一个字符串return "北京";// a是上一步异步线程返回的结果}, ThreadPoolUtils.getThreadPool()).thenApply(a -> {if ("北京".equals(a)) {return 1;} else {return 0;}});System.out.println(future.get());CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {// 返回一个字符串return "北京";// 重新再创建一个CompleteFuture}, ThreadPoolUtils.getThreadPool()).thenCompose(a -> CompletableFuture.supplyAsync(() -> {if ("北京".equals(a)) {return 1;} else {return 0;}}));System.out.println(completableFuture.get());}
结果

1

1
1

thenAccept和thenRun 

 thenAccept和thenRun:进行返回值回调。这样CompletableFuture就会没有返回值

源码
public CompletableFuture<Void> thenAccept(Consumer<? super T> action) {return uniAcceptStage(null, action);}public CompletableFuture<Void> thenRun(Runnable action) {return uniRunStage(null, action);}
案例
public static void main(String[] args) throws ExecutionException, InterruptedException {//模拟计算 1+1+1CompletableFuture future = CompletableFuture.supplyAsync(() -> {return 1;}, ThreadPoolUtils.getThreadPool()).thenApply(a -> a + 1).thenAccept(b -> System.out.println(b + 1));System.out.println("thenAccept返回了什么?" + future.get());CompletableFuture future2 = CompletableFuture.supplyAsync(() -> {return 1;}, ThreadPoolUtils.getThreadPool()).thenApply(a -> a + 1).thenRun(()->{System.out.println("----------线程运行----------");});System.out.println("thenRun返回了什么?" + future2.get());}
结果

3
thenAccept返回了什么?null
----------线程运行----------
thenRun返回了什么?null

两者区别:两者入参不同, thenRun参数是Runnable ,thenAccept参数是Consumer<? super T> action,thenAccept可以拿到上一步获取到的值。

complete

complete()方法用于手动完成一个异步任务,并设置其结果。一旦调用complete()方法,CompleteFuture对象的状态会立即变成已完成。如果多个线程尝试调用complete()方法,只有第一个成功的线程能够设置结果,其他线程调用将被忽略

源码
public boolean complete(T value) {boolean triggered = completeValue(value);postComplete();return triggered;
}
案例
public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {return "10";}, ThreadPoolUtils.getThreadPool());future.complete("1000");future.complete("10000");//输出1000System.out.println(future.get());}
结果

调用complete以后:1000

whenComplete

whenComplete是一个回调方法,会将CompletableFuture执行的结果和异常传递给它,如果是正常执行,则异常为null,如果异常,则get()方法会抛出异常。

源码
public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action) {return uniWhenCompleteStage(null, action);}
案例
public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {return "10";}, ThreadPoolUtils.getThreadPool()).whenComplete((v,e)->{System.out.println("获取到的异常:"+e);System.out.println("获取到的值:"+v);});// 这个地方会抛出异常System.out.println("whenComplete无异常回调以后以后:" + completableFuture.get());CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {int i = 1 / 0;return "10";}, ThreadPoolUtils.getThreadPool()).whenComplete((v,e)->{System.out.println("获取到的异常:"+e);System.out.println("获取到的值:"+v);});// 这个地方会抛出异常System.out.println("whenComplete有异常回调以后:" + future.get());}
结果 
获取到的异常:null
获取到的值:10
whenComplete无异常回调以后以后:10
获取到的异常:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
获取到的值:null
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zeroat java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)at com.common.base.util.CompletableFutureTest2.main(CompletableFutureTest2.java:30)
Caused by: java.lang.ArithmeticException: / by zeroat com.common.base.util.CompletableFutureTest2.lambda$main$2(CompletableFutureTest2.java:23)at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:748)

exceptionally 

exceptionally()对CompletableFuture异常进行捕获处理,并且设定一个返回值

源码
public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn) {return uniExceptionallyStage(fn);}
案例
public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {int i = 1 / 0;return "10";}, ThreadPoolUtils.getThreadPool()).exceptionally(e -> {//e.printStackTrace();System.out.println("执行的异常:" + e.getMessage());return "捕获异常以后自定义返回值";});System.out.println("捕获异常以后:" + future.get());}
结果
执行的异常:java.lang.ArithmeticException: / by zero
捕获异常以后:捕获异常以后自定义返回值

注意:大多数的时候我们通常都会把whenComplete+exceptionally结合起来一起使用

 whenComplete+exceptionally案例

Callable、Future和FutrueTask详解-CSDN博客

有这么一个问题,你的女朋友正在炒菜,发现厨房没盐了,需要你把新买的盐拿过来,如果使用FutureTask,那么会造成阻塞,现在使用CompletFuture来解决这个问题

public static void main(String[] args) throws InterruptedException {System.out.println("------------女朋友开始炒菜----------------");try {CompletableFuture.supplyAsync(() -> {return "让男朋友去买盐";}, ThreadPoolUtils.getThreadPool()).whenComplete((v, e) -> {if (e == null) {System.out.println("获取到任务:" + v);}}).exceptionally(e -> {e.printStackTrace();System.out.println("执行异常:" + e.getCause());return null;});System.out.println("----------女朋友继续炒菜-----------------");Thread.sleep(2000);System.out.println("-----------------女朋友炒菜结束--------------");} catch (Exception e) {e.printStackTrace();}}
结果

------------女朋友开始炒菜----------------
获取到任务:让男朋友去买盐
----------女朋友继续炒菜-----------------
-----------------女朋友炒菜结束--------------

通过上面代码我们可以知道,主线程女朋友炒菜可以一步都到底,不会出现线程阻塞的情况

 handle

handle()方法是一个回调方法,跟whenComplete没有多大的区别,唯一的区别是handle有返回值

源码
public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn) {return uniHandleStage(null, fn);}
案例
public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {return "10";}, ThreadPoolUtils.getThreadPool()).handle((v, e) -> {System.out.println("不存在异常的值" + e);System.out.println("上一步返回值:" + v);return "100";});//这个地方会抛出异常System.out.println("无异常回调handle以后:" + future.get());CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {int i = 1 / 0;return "10";}, ThreadPoolUtils.getThreadPool()).handle((v, e) -> {System.out.println("不存在异常的值" + e);System.out.println("上一步返回值:" + v);return "返回异常" + e.getMessage();});//这个地方会抛出异常System.out.println("有异常回调handle以后:" + completableFuture.get());}
结果

不存在异常的值:null
上一步返回值:10
无异常回调handle以后:100
不存在异常的值:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
上一步返回值:null
有异常回调handle以后:返回异常java.lang.ArithmeticException: / by zero

 allof

allof是将多个CompletableFuture合并在一起

源码
    public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {return andTree(cfs, 0, cfs.length - 1);}
案例
 public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {return "用户信息";}, ThreadPoolUtils.getThreadPool());//角色idCompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}return "角色信息";}, ThreadPoolUtils.getThreadPool());// 组合用户和角色idCompletableFuture future2 = CompletableFuture.allOf(future, future1);CompletableFuture<String> completableFuture = future2.thenApply(a -> {return future.join()+" " + future1.join();});//通过回调函数,获取对应的结果集System.out.println("等待两个线程执行完毕,进行合并" + completableFuture.join());}
结果

等待两个线程执行完毕,进行合并用户信息 角色信息

anyOf

多个任务中,那个任务先返回,就先返回哪个结果 

源码
   public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {return orTree(cfs, 0, cfs.length - 1);}
案例
public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {return "用户信息";}, ThreadPoolUtils.getThreadPool());//角色idCompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}return "角色信息";}, ThreadPoolUtils.getThreadPool());// 组合用户和角色idCompletableFuture future2 = CompletableFuture.anyOf(future, future1);System.out.println("anyOf谁先执行完,谁就先返回:" + future2.join());}
结果

anyOf谁先执行完,谁就先返回:用户信息

提示

CompletableFuture提供了很多方法,上面的方法都是CompletableFuture提供的同步方法,如果在上面的方法后缀加上Async,那么成了调用它的异步方法,比如thenApplyAsync()。

参考文章:CompletableFuture使用详解 - 简书

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

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

相关文章

ZooKeeper的分布式锁---客户端命令行测试(实操课程)

本系列是zookeeper相关的实操课程&#xff0c;课程测试环环相扣&#xff0c;请按照顺序阅读测试来学习zookeeper。阅读本文之前&#xff0c;请先阅读----​​​​​​zookeeper 单机伪集群搭建简单记录&#xff08;实操课程系列&#xff09;。 阅读本文之前&#xff0c;请先阅读…

从零开始的c语言日记day38——数组参数,指针参数

一维数组传参 要把数组或者指针传给函数&#xff0c;那函数参数如何设计&#xff1f; 上面各写法有问题嘛&#xff1f; 第一个没问题 第二个没问题 第三个没问题 第四个没问题 第五个解析&#xff1a;定义int*arr2[20]为20个int*类型的数组&#xff0c;test2之后用的是ar…

【Java学习笔记】73 - 正则表达式

项目代码 https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_Chapter27/src/com/yinhai/regexp 一、引入正则表达式 1.提取文章中所有的英文单词 2.提取文章中所有的数字 3.提取文章中所有的英文单词和数字 4.提取百度热榜标题 正则表达式是处理文本的利器…

Python之内置函数和模块

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

贪心算法策略实现

贪心算法 贪心算法&#xff1a;基于某种情况进行一个排序。 贪心算法得到的是优良解&#xff0c;而非全局最优解。需要证明局部最优解 全局最优解 经典贪心算法 —— 会议问题 对于这个问题 &#xff0c;我们提出贪心策略&#xff1a; 策略1&#xff1a;按照会议的持续时间长…

高效办公:如何使用视频剪辑工具批量转码,mp4视频到TS视频

在视频处理过程中&#xff0c;转码是一项常见的任务。将MP4视频转换为TS视频可以提供许多优势&#xff0c;包括更好的兼容性、更广泛的设备和平台支持以及更高的视频质量。然而&#xff0c;手动转码大量视频文件可能会非常耗时且效率低下。为了实现高效办公&#xff0c;可以使用…

RabbitMQ快速学习之WorkQueues模型、三种交换机、消息转换器(基于SpringBoot)

文章目录 前言一、WorkQueues模型消息发送消息接收能者多劳 二、交换机类型1.Fanout交换机消息发送消息接收 2.Direct交换机消息接收消息发送 3.Topic交换机消息发送消息接收 三、编程式声明队列和交换机fanout示例direct示例基于注解 四、消息转换器总结 前言 WorkQueues模型…

亚马逊云科技 re:Invent 2023:引领科技前沿,探索未来云计算之窗

文章目录 一、前言二、什么是亚马逊云科技 re:Invent&#xff1f;三、亚马逊云科技 re:Invent 2023 将于何时何地举行四、亚马逊云科技 re:Invent 2023 有什么内容&#xff1f;4.1 亚马逊云科技 re:Invent 2023 主题演讲4.2 亚马逊云科技行业专家探实战 五、更多亚马逊云科技活…

人工智能原理复习--知识表示(二)

文章目录 上一篇产生式表示法推理方式 结构化表示语义网络语义网络表示知识的方法和步骤应用题目 框架表示法下一篇 上一篇 人工智能原理复习–知识表示&#xff08;一&#xff09; 产生式表示法 把推理和行为的过程用产生式规则表示&#xff0c;所以又称基于规则的系统。 产…

哈希_快乐数

//编写一个算法来判断一个数 n 是不是快乐数。 // // 「快乐数」 定义为&#xff1a; // // // 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。 // 然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终变不到 1。 // 如果…

LTD253次升级 | 官网“活动“增报名 • 名片展示个人简介 • 合伙人设置个性邀请码

1、活动类型支持报名&#xff1b; 2、产品详情页支持房产类型产品的地图显示&#xff1b; 3、官微名片独立版支持个人简介&#xff1b; 4、多语言系统支持挪威语&#xff1b; 5、极速官微首页提速、合伙人页面优化&#xff1b; 6、 已知问题优化与修复&#xff1b; 01网站编辑器…

陪诊系统:基于自然语言处理的患者沟通创新

医疗领域的数字化转型正日益引入创新技术&#xff0c;其中基于自然语言处理&#xff08;NLP&#xff09;的陪诊系统成为提升患者沟通的一项关键技术。本文将深入研究这一领域&#xff0c;介绍陪诊系统如何借助NLP实现患者沟通的创新&#xff0c;并提供一个简单的Python代码示例…