【Java】CompletableFuture学习记录

news2024/11/18 3:28:55

目录

  • 介绍
  • 创建异步对象
  • 计算完成时回调方法
  • handle 方法
  • 线程串行化方法
  • 两任务组合 - 都要完成
  • 两任务组合 - 一个完成
  • 多任务组合

介绍

业务场景:查询商品详情页的逻辑比较复杂,有些数据还需要远程调用,必然需要花费更多的时间。
在这里插入图片描述
假如商品详情页的每个查询,需要如下标注的时间才能完成。那么,用户需要 5.5s 后才能看到商品详情页的内容。很显然是不能接受的。如果有多个线程同时完成这 6 步操作,也许只需要 1.5s 即可完成响应。

Future 是 Java 5 添加的类,用来描述一个异步计算的结果。你可以使用isDone方法检查计算是否完成,或者使用get阻塞住调用线程,直到计算完成返回结果,你也可以使用cancel 方法停止任务的执行。

虽然Future以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不方便,只能通过阻塞或者轮询的方式得到任务的结果。阻塞的方式显然和我们的异步编程的初衷相违背,轮询的方式又会耗费无谓的 CPU 资源,而且也不能及时地得到计算结果,为什么不能用观察者设计模式当计算结果完成及时通知监听者呢?

很多语言,比如 Node.js,采用回调的方式实现异步编程。Java 的一些框架,比如Netty,自己扩展了 Java 的 Future接口,提供了addListener等多个扩展方法;Google guava 也提供了通用的扩展 Future;Scala 也提供了简单易用且功能强大的 Future/Promise 异步编程模式。

作为正统的 Java 类库,是不是应该做点什么,加强一下自身库的功能呢?

在 Java 8 中, 新增加了一个包含 50 个方法左右的类: CompletableFuture,提供了非常强大的Future 的扩展功能,可以帮助我们简化异步编程的复杂性,提供了函数式编程的能力,可以通过回调的方式处理计算结果,并且提供了转换和组合 CompletableFuture 的方法。CompletableFuture 类实现了 Future 接口,所以你还是可以像以前一样通过get方法阻塞或者轮询的方式获得结果,但是这种方式不推荐使用。

CompletableFuture 和 FutureTask 同属于 Future 接口的实现类,都可以获取线程的执行结果。
在这里插入图片描述

创建异步对象

CompletableFuture 提供了四个静态方法来创建一个异步操作。
在这里插入图片描述
1、runXxxx 都是没有返回结果的,supplyXxx 都是可以获取返回结果的
2、可以传入自定义的线程池,否则就用默认的线程池;

public class CompletableFutureTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("异步任务执行");
            return 1;
        }, executorService);

        System.out.println("异步任务返回值:" + future.get());
        System.out.println("主线程执行");
        executorService.shutdown();
    }
}

运行结果:
在这里插入图片描述

public class CompletableFutureTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            System.out.println("异步任务执行,无返回值");
        }, executorService);

        System.out.println("异步任务返回值:" + future.get());
        System.out.println("主线程执行");
        executorService.shutdown();
    }
}

运行结果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/65d74d42e0ad4d9196a393c621cf2aad.png

计算完成时回调方法

在这里插入图片描述
whenComplete 可以处理正常和异常的计算结果,exceptionally 处理异常情况。
whenCompletewhenCompleteAsync 的区别:
whenComplete:是执行当前任务的线程执行继续执行 whenComplete 的任务。whenCompleteAsync:是执行把 whenCompleteAsync 这个任务继续提交给线程池来进行执行。

public class CompletableFutureTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            return 1;
        }, executorService).whenComplete((res, throwable) -> {
            System.out.println("接收supplyAsync处理结果:" + res);
            if (throwable != null) {
                System.out.println("supplyAsync出现异常:" + throwable);
            }
        });

        executorService.shutdown();
    }
}

运行结果:
在这里插入图片描述

方法不以 Async 结尾,意味着 Action 使用相同的线程执行,而 Async 可能会使用其他线程执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)

handle 方法

在这里插入图片描述
和 complete 一样,可对结果做最后的处理(可处理异常),可改变返回值。

public class CompletableFutureTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            return 1 / 0;
        }, executorService).handle((res, throwable) -> {
            System.out.println("接收supplyAsync处理结果" + res);
            if (throwable != null) {
                System.out.println("接收supplyAsync异常:" + throwable);
            }
            return 10;
        });

        System.out.println("返回默认值" + future.get());
        executorService.shutdown();
    }
}

在这里插入图片描述

线程串行化方法

在这里插入图片描述
thenApply 方法:当一个线程依赖另一个线程时,获取上一个任务返回的结果,并返回当前任务的返回值。
thenAccept 方法:消费处理结果。接收任务的处理结果,并消费处理,无返回结果。
thenRun 方法:只要上面的任务执行完成,就开始执行 thenRun,只是处理完任务后,执行thenRun 的后续操作

        /*
        thenRunAsync():不能获取上一步的执行结果,无返回值
         */
        CompletableFuture<Void> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("异步任务1执行");
            return 10;
        }, executorService).thenRunAsync(() -> {
            System.out.println("异步任务2执行");
        }, executorService);
        /*
        thenAcceptAsync():可以获取上一步的执行结果,无返回值
         */
        CompletableFuture<Void> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("异步任务1执行");
            return 10;
        }, executorService).thenAcceptAsync(res -> {
            System.out.println("异步任务2执行,拿到任务1的返回结果" + res);
        }, executorService);
        /*
        thenApplyAsync():可以获取上一步的执行结果,可以返回值
         */
        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("异步任务1执行");
            return 10;
        }, executorService).thenApplyAsync(res -> {
            System.out.println("异步任务2执行,拿到任务1的返回结果" + res);
            return 20;
        }, executorService);

两任务组合 - 都要完成

在这里插入图片描述
两个任务必须都完成,触发该任务。

thenCombine:组合两个 future,获取两个 future 的返回结果,并返回当前任务的返回值
thenAcceptBoth:组合两个 future,获取两个 future 任务的返回结果,然后处理任务,没有返回值。
runAfterBoth:组合两个 future,不需要获取 future 的结果,只需两个future 处理完任务后,处理该任务。

两个任务future2future3 都要干完的情况

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("异步任务1执行");
            return 10;
        }, executorService);

        CompletableFuture<Integer> future3 = CompletableFuture.supplyAsync(() -> {
            System.out.println("异步任务2执行");
            return 20;
        }, executorService);

        /*
        future2和future3都执行完成后,在进行操作
        runAfterBothAsync不能感知到前两个异步任务的返回结果
         */
        CompletableFuture<Void> future = future2.runAfterBothAsync(future2, () -> {
            System.out.println("任务3开始");
        }, executorService);
        System.out.println(future2.get());
        future2.thenAcceptBothAsync(future3, (res1, res2) -> {
            System.out.println("任务1和任务2返回结果" + res1 + res2);
        }, executorService);
        future2.thenCombineAsync(future3, (res1, res) -> {
            return 30;
        }, executorService);

两任务组合 - 一个完成

在这里插入图片描述
当两个任务中,任意一个 future 任务完成的时候,执行任务。

applyToEither:两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值。acceptEither:两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值。runAfterEither:两个任务有一个执行完成,不需要获取 future 的结果,处理任务,也没有返回值。

多任务组合

在这里插入图片描述
allOf:等待所有任务完成
anyOf:只要有一个任务完成

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

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

相关文章

socket网络编程中设置socket选项的ioctlsocket、setsockopt和WSAIoctl函数的使用(附源码)

VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&#xff09;https://blog.csdn.net/chenlycly/article/details/124272585C软件异常排查从入门到精通系列教程&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&a…

AI发展历史

一、AI的发展历史 二、AI发展的第五阶段 &#xff08;一&#xff09;、第一阶段 1.艾伦图灵与模仿游戏 艾伦•图灵&#xff08;Alan Turing&#xff0c;1912~1954&#xff09;是英国数学家、逻辑学家&#xff0c;被称为计算机科学之父&#xff0c;人工智能之父。二战中协助军…

vue重修004【下部】

文章目录 版权声明非父子通信event bus 事件总线实现步骤代码演示 非父子通信-provide&inject语法注意代码演示 v-model原理表单类组件封装& v-model 简化代码.sync修饰符语法代码示例 ref 和 $refs语法代码演示 异步更新 & $nextTick引子$nextTick演示 版权声明 …

javaee ssm框架项目添加分页控件

搭建ssm框架项目 参考上一篇博文 添加分页控件 引入依赖 <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schema…

关联规则挖掘(下):数据分析 | 数据挖掘 | 十大算法之一

⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ &#x1f434;作者&#xff1a;秋无之地 &#x1f434;简介&#xff1a;CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作&#xff0c;主要擅长领域有&#xff1a;爬虫、后端、大数据…

Kubernetes安装部署 1

本文主要描述kubernetes的安装部署&#xff0c;kubernetes的安装部署主要包括三个关键组件&#xff0c;其中&#xff0c;包括kubeadm、kubelet、kubectl&#xff0c;这三个组件的功能描述如下所示&#xff1a; Kubeadm 用于启动与管理kubernetes集群 Kubelet 运行在所有集群的…

[晕事]今天做了件晕事21;设置代理访问网站的时候需注意的问题

今天在家上班&#xff0c;设置好VPN&#xff0c;通过代理来访问公司内部的一个系统浏览器的反应如下&#xff1a; Hmmm… can’t reach this page ***.com refused to connect. 这个返回的错误&#xff0c;非常的具有迷惑性&#xff0c;提示的意思&#xff1a;拒绝链接&#xf…

Kaggle - LLM Science Exam(二):Open Book QAdebertav3-large详解

文章目录 前言&#xff1a;优秀notebook介绍三、Open Book Q&A3.1 概述3.2 安装依赖&#xff0c;导入数据3.3 数据预处理3.3.1 处理prompt3.3.2 处理wiki数据 3.4 使用faiss搜索获取匹配的Prompt-Sentence Pairs3.5 查看context结果并保存3.6 推理3.6.1 加载测试集3.6.2 定…

模型压缩部署概述

模型压缩部署概述 一&#xff0c;模型在线部署 1.1&#xff0c;深度学习项目开发流程 1.2&#xff0c;模型训练和推理的不同 二&#xff0c;手机端CPU推理框架的优化 三&#xff0c;不同硬件平台量化方式总结 参考资料 一&#xff0c;模型在线部署 深度学习和计算机视觉…

POJ 3264 Balanced Lineup 线段树 / 平方分割

一、题目大意 给出一个长度为 n&#xff08;n<50000) 数组 arr&#xff0c;进行Q次查询&#xff08;Q<200000&#xff09;&#xff0c;每次查询的内容为数组arr在 [L , R] 的切片的极差&#xff08;最大元素 - 最小元素&#xff09; 二、解题思路 1、线段树 区间极差…

[每周一更]-(第65期):Docker容器监控工具推荐

Docker 容器化监控工具用于监视和管理 Docker 容器的性能、资源使用情况、日志、事件和状态等。以下是一些常用的 Docker 容器监控工具&#xff1a; Docker 自带的监控功能: Docker Stats: Docker 内置的命令&#xff0c;用于实时显示运行中容器的资源使用情况&#xff0c;包括…

QGIS文章五——对遥感影像进行土地类型分类-选择遥感影像

关于下载遥感影像的地方有很多&#xff1a; 1、国家综合地球观测数据共享平台&#xff08;https://www.chinageoss.cn/&#xff09; 2、地理空间数据云&#xff08;https://www.gscloud.cn/&#xff09; 3、美国地质勘探局官网&#xff08;https://earthexplorer.usgs.gov/&…

RabbitMQ之Direct(直连)Exchange解读

目录 基本介绍 使用场景 springboot代码演示 演示架构 工程概述 RabbitConfig配置类&#xff1a;创建队列及交换机并进行绑定 MessageService业务类&#xff1a;发送消息及接收消息 主启动类RabbitMq01Application&#xff1a;实现ApplicationRunner接口 基本介绍 在r…

【多线程进阶】CAS实现及应用

文章目录 前言1. 什么是 CAS2. CAS 是如何实现的3. CAS 有哪些应用3.1 实现原子类3.2 实现自旋锁 4. CAS 中 ABA 问题4.1 ABA 问题是什么4.2 ABA 引发的问题4.3 解决方案 总结 前言 上文讲解 synchronized 当提到自旋锁时, 讲到当其他线程进入竞争, 偏向锁状态被消除, 就会进入…

简单聊一聊公平锁和非公平锁,parallel并行流

目录 一、降低锁的粒度&#xff0c;将synchronized关键字不放在方法上了&#xff0c;改为synchronized代码块。二、先区分一下公平锁和非公平锁1、公平锁2、非公平锁3、公平锁的优缺点&#xff1a;4、非公平锁的优缺点&#xff1a; 三、是否对症下药四、IntStream.rangeClosed是…

C++ - C++11历史 - 统一列表初始化 - aotu - decltype - nullptr - C++11 之后 STL 的改变

C的发展史了解 在2003年C标准委员会曾经提交了一份技术勘误表(简称TC1)&#xff0c;使得C03这个名字已经取代了C98称为C11之前的最新C标准名称。 不过由于C03(TC1)主要是对C98标准中的漏洞进行修复&#xff0c;语言的核心部分则没有改动&#xff0c;因此人们习惯性的把两个标…

15046-2011 脂肪酰二乙醇胺 学习笔记

声明 本文是学习GB-T 15046-2011 脂肪酰二乙醇胺.pdf而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了脂肪酰二乙醇胺的产品分类、要求、试验方法、检验规则和标志、包装、运输、贮存和保 质期。 本标准适用于由脂肪酸甲酯或脂肪…

C++(反向迭代器)

前言&#xff1a; 上一章我们介绍了适配器&#xff0c;也提了一下迭代器适配器&#xff0c;今天我们就从反向迭代器把迭代器适配器给解释一下。 既然 都叫迭代器容器了 就说名只要接口合适他可以封装实现各种容器需求包括vector list 。 目录 1.反向迭代器设计 1.1反向迭代…

浅谈电气防火限流式保护器在小型人员密集场所中的应用

摘要&#xff1a;本文通过结合城市中小型人员密集场所的特点和电气防火限流式保护器的功能&#xff0c;阐述了该类筑物预防电气火灾事故的方法。 关键词&#xff1a;小型人员密集场所&#xff1b;电气防火限流式保护器 0&#xff1a;概述 近年来&#xff0c;随着社会经济的不…

C++标准模板(STL)- 类型支持 (定宽整数类型)(INT8_C,INTMAX_C,UINT8_C,UINTMAX_C,格式化宏常量)

最小宽度整数常量的函数宏 INT8_CINT16_CINT32_CINT64_C 展开成拥有其实参所指定的值且类型分别为 int_least8_t、int_least16_t、int_least32_t、int_least64_t 的整数常量表达式 (宏函数) INTMAX_C 展开成拥有其实参所指定的值且类型为 intmax_t 的整数常量表达式 (宏函数) U…