Java并发-CompletableFuture的详解

news2024/11/18 21:41:49

目录

1 前言

 2 常用方法

3 测试

3.1 runAsync:无返回值 和 SupplyAsync:有返回值

 3.2 串行执行

3.3 任务3等待等任务1和任务2都执行完毕后执行

3. 4 任务3等待等任务1或者任务2执行完毕后执行

3.5 handleAsync

3.6 多任务执行


1 前言

CompletableFuture 是对 Future 的扩展和增强。CompletableFuture 实现了Future和CompletionStage接口,其中最重要的是CompletionStage,它定义了CompletableFuture 实现任务编排的一些基本方法。只能说非常好用。

其继承结构如下图所示,在IDEA中使用ctrl + alt + U 实现

 CompletionStage接口定义了任务编排的方法,执行某一阶段,可以向下执行后续阶段。异步执行的,默认线程池是ForkJoinPool.commonPool(),但为了业务之间互不影响,且便于定位问题,强烈推荐使用自定义线程池

 2 常用方法

主要有同步和异步两大类,这里只讲异步方法。同步方法可以类比。

创建类型的方法

  • runAsync:无返回值
  • SupplyAsync:有返回值

中间处理类型的方法

  • 任务与任务之间串行执行
    • thenRunAsync:不能获取上一次的返回值,本次没有返回值。
    • thenAccpetAsync:获取上一次的返回值,但是本次没有返回值。
    • thenApplyAsync:获取上一次的返回值,本次返回值。
  • 任务3等待等任务1和任务2都执行完毕后执行
    • runAfterBothAsync:不能获取任务1和任务2的返回值,本次没有返回值。
    • thenAcceptBothAsync:获取任务1和任务2的返回值,但是本次没有返回值。
    • thenCombineAsync:获取任务1和任务2的返回值,本次也有返回值。
  • 任务3等待任务1或者任务2其中一个执行完毕、
    • runAfterEitherAsync:不能获取任务1或任务2的返回值,本次没有返回值
    • acceptEitherAsync:获取任务1或任务2的返回值,本次没有返回值
    • applyToEither:获取任务1或任务2的返回值,本次有返回值
  • 多任务
    • allof:当所有给定的 CompletableFuture 完成时,返回一个新的 CompletableFuture
    • anyof:当任何一个给定的CompletableFuture完成时,返回一个新的CompletableFuture

结果处理类型的方法

  • whenCompleteAsync:获取结果和异常,但是没有返回值
  • exceptionally:在whenCompleteAsync后时候,获取异常并且有返回值
  • handleAsync:相当于whenCompleteAsync和exceptionally的结合体。

3 测试

3.1 runAsync:无返回值 和 SupplyAsync:有返回值

  • runAsync 相当于开启一个异步线程执行任务,主线程不等待结果返回。
  • supplyAsync,开启一个异步线程执行任务,主线程要等待结果返回。
package cn.itcast.n6.c3;

import java.util.concurrent.*;

/**
 * @author : msf
 * @date : 2022/12/4
 * completable 讲解。
 */
public class CompletableFutureD1 {
    static ThreadPoolExecutor executor = new ThreadPoolExecutor(
            5,50,10, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(100),Executors.defaultThreadFactory()
            ,new ThreadPoolExecutor.AbortPolicy()
    );
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("主线程 start ...");
       CompletableFuture<Void> future = CompletableFuture.runAsync(()->{
           System.out.println("任务1子线程执行..." + Thread.currentThread().getName());
       },executor);

        CompletableFuture<Integer> futureInt = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2子线程执行..." + Thread.currentThread().getName());
            return 10;
        }, executor);

        System.out.println(futureInt.get());
        System.out.println("主线程 end ...");
    }
}

上述代码执行结果:

 3.2 串行执行

  • thenRunAsync:不能获取上一次的返回值,本次没有返回值。
  • thenAccpetAsync:获取上一次的返回值,但是本次没有返回值。
  • thenApplyAsync:获取上一次的返回值,本次返回值

package cn.itcast.n6.c3;

import java.util.concurrent.*;

/**
 * @author : msf
 * @date : 2022/12/4
 * completable 讲解--串行编排
 */
public class CompletableFutureD4 {
    static ThreadPoolExecutor executor = new ThreadPoolExecutor(
            5, 50, 10, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(100), Executors.defaultThreadFactory()
            , new ThreadPoolExecutor.AbortPolicy()
    );

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("主线程 start ...");
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            System.out.println("任务1子线程执行..." + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, executor).thenRunAsync(()->{
            // 等任务1 执行完毕后,任务2执行
            System.out.println("任务2执行了" +Thread.currentThread().getName());
        },executor);


        CompletableFuture.supplyAsync(() -> {
            System.out.println("任务3子线程执行..." + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 100;
        }, executor).thenAcceptAsync((t)->{
            System.out.println("任务4子线程执行..." + Thread.currentThread().getName());
            System.out.println("t = " + t);
        },executor);

        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务5子线程执行..." + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 100;
        }, executor).thenApplyAsync((t) -> {
            System.out.println("任务6子线程执行..." + Thread.currentThread().getName());
            System.out.println("t = " + t);
            return 120;
        }, executor);
        System.out.println("主线程 end ..." + future1.get());

    }
}

上述代码执行结果:

3.3 任务3等待等任务1和任务2都执行完毕后执行

开启一个任务1,然后开启任务2,我们需要的是,当任务1和2都执行结束后任务3再启动。

场景:例如两个人从不同地方去吃饭,都有两个人都到了然后开始点餐。

package cn.itcast.n6.c3;

import java.util.concurrent.*;

/**
 * @author : msf
 * @date : 2022/12/4
 * completable 讲解-- 两个一起完成,或者两者其中之一完成
 */
public class CompletableFutureD5 {
    static ThreadPoolExecutor executor = new ThreadPoolExecutor(
            5, 50, 10, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(100), Executors.defaultThreadFactory()
            , new ThreadPoolExecutor.AbortPolicy()
    );

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("主线程 start ...");
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            System.out.println("任务1子线程执行..." + Thread.currentThread().getName());
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, executor);


        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2子线程执行..." + Thread.currentThread().getName());
            try {
                Thread.sleep(600);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 100;
        }, executor);

        future.runAfterBothAsync(future1, () -> {
            System.out.println("任务3..." + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("任务3.... end " + Thread.currentThread().getName());
        }, executor);

        System.out.println("主线程 end ..." + future1.get());

    }
}

上述代码执行结果: 

3. 4 任务3等待等任务1或者任务2执行完毕后执行

场景:当两个人都出去吃饭,其中一个人到了可以先点餐。

package cn.itcast.n6.c3;

import java.util.concurrent.*;

/**
 * @author : msf
 * @date : 2022/12/4
 * completable 讲解-- 两个一起完成,或者两者其中之一完成
 */
public class CompletableFutureD6 {
    static ThreadPoolExecutor executor = new ThreadPoolExecutor(
            5, 50, 10, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(100), Executors.defaultThreadFactory()
            , new ThreadPoolExecutor.AbortPolicy()
    );

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("主线程 start ...");
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            System.out.println("任务1子线程执行..." + Thread.currentThread().getName());
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("任务1子线程执行...end " + Thread.currentThread().getName());
        }, executor);


        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2子线程执行..." + Thread.currentThread().getName());
            try {
                Thread.sleep(600);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("任务2子线程执行...end " + Thread.currentThread().getName());
            return 100;
        }, executor);

        future.runAfterEitherAsync(future1, () -> {
            System.out.println("任务3..." + Thread.currentThread().getName());
        }, executor);

        System.out.println("主线程 end ..." + future1.get());

    }
}

上述代码执行如下: 

3.5 handleAsync

handleAsync:相当于whenCompleteAsync和exceptionally的结合体,可以收集结果和异常信息然后进行下一步处理。

package cn.itcast.n6.c3;

import java.util.concurrent.*;

/**
 * @author : msf
 * @date : 2022/12/4
 * completable 讲解。
 */
public class CompletableFutureD3 {
    static ThreadPoolExecutor executor = new ThreadPoolExecutor(
            5, 50, 10, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(100), Executors.defaultThreadFactory()
            , new ThreadPoolExecutor.AbortPolicy()
    );

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("主线程 start ...");
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            System.out.println("任务1子线程执行..." + Thread.currentThread().getName());
        }, executor).handleAsync((res, exec) -> {
            System.out.println("res1 = " + res);
            System.out.println("exec1 = " + exec);
            return null;
        });
        CompletableFuture<Integer> futureInt = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2子线程执行..." + Thread.currentThread().getName());
            int i = 10 / 0;
            return 10;
        }, executor).handleAsync((res, exec) -> {
            System.out.println("res2 = " + res);
            System.out.println("exec2 = " + exec);
            return 55;
        });

        System.out.println(futureInt.get());
        System.out.println("主线程 end ...");
    }
}

上述代码执行结果:

3.6 多任务执行

模拟:三人吃饭,只要一个人到了就可以点餐,但是只有所有人到了,并且厨子把菜做好了才能上菜;

package cn.itcast.n6.c3;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * @author : msf
 * @date : 2022/12/5
 * 模拟三人点餐,只要有一个人到了就可以点餐。然后交给厨子进行做饭
 */
public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        long begin = System.currentTimeMillis();
        CompletableFuture<Void> client1 = CompletableFuture.runAsync(() -> {
            System.out.println("客户1开始出发了.....1小时后到");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("客户1到了");
        });
        CompletableFuture<Void> client2 = CompletableFuture.runAsync(()->{
            System.out.println("客户2开始出发了.....半小时后到");
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("客户2到了");
        });
        CompletableFuture<Void> client3 = CompletableFuture.runAsync(()->{
            System.out.println("客户3开始出发了.....1.5小时后到");
            try {
                Thread.sleep(1500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("客户3到了");
        });
        CompletableFuture<Object> result = CompletableFuture.anyOf(client1, client2, client3);
        System.out.println("已经有客户到了开始点餐" +result.get());

        CompletableFuture<Void> cook = CompletableFuture.runAsync(() -> {
            System.out.println("厨师开始做饭");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("厨师做完饭了");
        });
        CompletableFuture<Void> reuslt1 = CompletableFuture.allOf(client1, client2, client3, cook);
        reuslt1.join();
        System.out.println("人全部来齐了,厨师也做好饭了,上菜!");
        long end = System.currentTimeMillis();
        System.out.println("总共时间盲猜2.5秒, 真实时间" + (end - begin) );
    }
}

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

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

相关文章

LabVIEW中将前面板置于所有桌面窗口的前面

LabVIEW中将前面板置于所有桌面窗口的前面 想将前面板窗口设置在所有桌面窗口的前面。前面板属性IsFrontmost&#xff08;如下图所示&#xff09;将前面板设置为仅位于所有 LabVIEW 窗口的前面。如何将前面板置于所有桌面窗口的前面&#xff1f; 解决方案 如果使用位于C:\WIN…

【JavaWeb】第七章 Tomcat

文章目录1、JavaWeb2、Web资源与Web服务器3、Tomcat的使用4、部署Web工程到Tomcat中5、工程和资源的访问6、IDEA集成Tomcat服务器7、创建动态web工程1、JavaWeb JavaWeb是指通过Java语言编写的可以通过浏览器访问的程序的总称。 请求&#xff1a; 客户端给服务器发送数据&…

java基于SSM的婚纱影楼管理系统-计算机毕业设计

开发环境 开发工具:IDEA /Eclipse 数据库:MYSQL5.7 应用服务:Tomcat7/Tomcat8 使用框架:SSM(springspringMVCmybatis)vue 项目介绍 婚姻是每个人人生中都非常重要的一个组成部分&#xff0c;它是一个新家庭的开始也是爱情的见证&#xff0c;所以很多人在结婚之前都会拍一套美…

数字先锋 | 农业农村部大数据公共平台基座上线,天翼云擎起乡村振兴新希望!

近日&#xff0c;由中国农业农村部大数据发展中心牵头&#xff0c;联合中国电信集团有限公司、人民数据管理&#xff08;北京&#xff09;有限公司、北京中农信达信息技术有限公司、北京农信通科技有限责任公司共同打造的“农业农村大数据公共平台基座”已正式上线&#xff0c;…

借助云的力量,重塑企业的现在和未来|re:Invent 2022 Adam Selipsky 主题演讲精华全收录

2022 亚马逊云科技re:Invent全球大会进入第二天&#xff0c;亚马逊云科技首席执行官 Adam Selipsky 发表了“如何借助云的力量&#xff0c;在未知领域抓住机遇并茁壮成长”的主题演讲。在两个小时的演讲中&#xff0c;Adam 重点围绕数据、安全、计算性能和行业应用等4个主题发布…

问题 A: 二叉排序树 - 文本输出

题目描述 给定一个序列&#xff0c;使用该序列生成二叉排序树&#xff08;也叫二叉搜索树&#xff0c;BST&#xff09;&#xff0c;然后以本题规定方法输出该二叉排序树。 例&#xff1a; 给定一个序列&#xff1a;43 25 29 67 17 88 54 47 35 62 以第一个数字&#xff08;43&…

RFID防盗安全门,自助借还书机,让图书馆发展进入新的里程碑

RFID无线射频识别是一种非接触的自动识别技术&#xff0c;它通过射频信号自动识别目标对象并获取相关数据&#xff0c;可快速进行物品追踪和数据交换&#xff0c;其识别无需人工干预。 RFID作为一种新的技术&#xff0c;它不只是简单的磁条码替代品&#xff0c;它的运作让图书馆…

为什么说新一代BI是“面向业务的可视化分析工具”?

BI工具一直被誉为数据应用的“最后一公里”&#xff0c;其原因在于BI工具可以通过简洁的方式完成数据分析&#xff0c;将数据结果直观的展现给使用者&#xff0c;达到释放数据价值的目的。 然而&#xff0c;传统BI的根本问题在于操作难度大&#xff0c;导致只能专业的IT人员进…

(02)Cartographer源码无死角解析-(33) LocalTrajectoryBuilder2D: 点云数据流向、处理、消息发布等→流程复盘

讲解关于slam一系列文章汇总链接:史上最全slam从零开始&#xff0c;针对于本栏目讲解(02)Cartographer源码无死角解析-链接如下: (02)Cartographer源码无死角解析- (00)目录_最新无死角讲解&#xff1a;https://blog.csdn.net/weixin_43013761/article/details/127350885 文末…

反复重购,资金严重浪费?企业资产需要这样管理

很多企事业资产具有数量大、种类多、价值高、使用周期长、使用地点分散&#xff0c;管理难度大。一些传统固定资产管理软件&#xff0c;痛点丛生&#xff0c;已难于满足企事业需求。 资产管理业务4大现状 01.手段滞后 资产实际的使用状态及状况无法得到及时、准确地反馈。 02.…

「Redis数据结构」RedisObject

「Redis数据结构」RedisObject 文章目录「Redis数据结构」RedisObject一、概述二、结构三、编码方式四、小结五、参考一、概述 redisObject对象非常重要&#xff0c;Redis对象的类型、内部编码、内存回收、共享对象等功能&#xff0c;都需要redisObject支持。 redis 不是一个…

DPDK EAL

DPDK全程是Intel Data Plane Development Kit&#xff0c;是一个数据平面开发集。 DPDK的主要思想 绕过内核&#xff0c;实现Zero Copy使用UIO驱动屏蔽硬中断&#xff0c;并采用PMD主动轮询&#xff0c;减少Cache Miss和切换上下文的开销使用大页内存&#xff0c;减少TLB Mis…

重磅:Docker Desktop正式集成WasmEdge。后者首登GitHubTrending

上周五&#xff0c;Docker Desktop 发布了 4.15 新版本。在这个版本中&#xff0c;Docker Desktop 正式集成了 WasmEdge 的 containerd shim&#xff0c; 并且 Docker Wasm 也从 tech preview 进入到了 beta 阶段。这意味着&#xff0c;1000 万 Docker Desktop 的用户都安装了…

代码安全与质量 | 在这个充满变数的时代,花小钱办大事

在这个充满变数的时代&#xff0c;许多企业都想要提升效率&#xff0c;但如何以同样的时间、人力成本创造出更大的价值&#xff1f;在研发领域&#xff0c;企业选择引入更好的工具来帮助交付高质量代码&#xff0c;比如Sonar&#xff0c;帮助团队充分利用时间&#xff0c;专注于…

Gradle 使用maven本地仓库 带来的思考

Gradle 使用maven本地仓库 带来的思考 本篇主要探究一下 在使用Gradle 的时候一般会配置 maven 的本地仓库的,那是不是Gradle 可以直接使用 maven本地仓库的jar呢 ? 下面来探究一下 思考 当我们在使用Gradle的时候 一配置一个 mavenLocal() 代表它会使用maven的本地仓库, 此时…

独立产品灵感周刊 DecoHack #040 - Google公布2022年度最佳应用榜单

本周刊记录有趣好玩的独立产品设计开发相关内容&#xff0c;每周发布&#xff0c;往期内容同样精彩&#xff0c;感兴趣的伙伴可以点击订阅我的周刊。为保证每期都能收到&#xff0c;建议邮件订阅。欢迎通过 Twitter 私信推荐或投稿。&#x1f4bb; 产品推荐 1. Sensei 这是一…

408真题-2021

死去的记忆正在攻击我&#xff1a; [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n7aXxWnx-1670222893563)(https://waite1-1307752947.cos.ap-nanjing.myqcloud.com/img/202212051447504.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保…

网络编程之NIO 基础

一. NIO 基础 non-blocking io 非阻塞 IO 1. 三大组件 1.1 Channel & Buffer channel 有一点类似于 stream&#xff0c;它就是读写数据的双向通道&#xff0c;可以从 channel 将数据读入 buffer&#xff0c;也可以将 buffer 的数据写入 channel&#xff0c;而之前的 st…

数据结构与算法之Python实现——栈

在常用的数据结构中&#xff0c;有一批结构被称为容器——栈与队列。 本篇博客主要学习一下栈这种结构的特性&#xff0c;以及用python实现它的相关操作。 内容 顺序栈链栈栈的实际应用 在这之前&#xff0c;我们需要了解一下什么是栈&#xff0c;以及栈这种结构有什么用处&am…

HarmonyOS/OpenHarmony应用开发-DataAbility开发体验

场景介绍 基于Data模板的Ability&#xff08;以下简称“Data”&#xff09;&#xff0c;有助于应用管理其自身和其他应用存储数据的访问&#xff0c;并提供与其他应用共享数据的方法。Data既可用于同设备不同应用的数据共享&#xff0c;也支持跨设备不同应用的数据共享。 Dat…