【异步编程】CompletableFuture:异步任务的选择(执行最快的)执行

文章目录

    • 一. applyToEither : 拿到第一个任务结束的结果
    • 二. runAfterEither :第一个任务完成后执行副作用
    • 三. acceptEither:消费第一个任务的结果
    • 四. 三种接口总结

对于两个异步任务,我们有时希望在其中一个任务完成时立即执行某些操作,而不必等待其他任务的完成。为了实现这一需求,CompletionStage 提供了几个有用的方法,其中包括 applyToEither()runAfterEither()acceptEither()

CompletableFuture对异步任务的选择执行不是按照某种条件进行选择的,而是按照执行速度进行选择的:前面两个并行任务,谁的结果返回速度快,谁的结果将作为第三步任务的输入。

一. applyToEither : 拿到第一个任务结束的结果

applyToEither() 方法允许我们在两个异步任务中选择一个已经完成的任务,并对其结果应用一个函数。无论哪个任务先完成,都会执行传入的 Function 操作,并返回一个新的 CompletableFuture

方法签名:

public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, ? extends U> fn)

- **`other`**:另一个 `CompletionStage`,与当前任务并行执行。
- **`fn`**(两个任务中)当第一个任务完成时应用的函数。

使用场景:

applyToEither() 方法非常适合于需要在多个异步任务中选择一个最快完成的任务结果并进行处理的场景。

示例代码:

@Test  
public void applyToEitherDemo2() throws Exception {  
  
    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {  
        try {  
            Thread.sleep(500);  
        } catch (InterruptedException e) {  
            Thread.currentThread().interrupt();  
        }  
        return 2;  
    });  
  
    CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {  
        try {  
            Thread.sleep(100);  
        } catch (InterruptedException e) {  
            Thread.currentThread().interrupt();  
        }  
        return 3;  
    });  
  
    CompletableFuture<Integer> result = future1.applyToEither(future2, (result1) -> {  
        System.out.println("第一个完成的任务的结果: " + result1);  
        return result1 * 2;  // 对结果进行处理  
    });  
    Integer integer = result.get();  
    System.out.println(integer);  
  
}


分析

  • future1future2 两个异步任务并行执行。
  • applyToEither() 会选择第一个完成的任务,并将其结果传递给 fn
    这里是对结果进行乘以 2 的操作。
  • 如果 future2 完成更快(如上例中的500ms),则会输出 "第一个完成的任务的结果: 3" 并返回 6

 

二. runAfterEither :第一个任务完成后执行副作用

runAfterEither() 方法与 applyToEither() 类似,但它不关心任务的结果。它只在其中一个任务完成时执行一个没有返回值的操作。它适用于需要在多个任务中选择一个最先完成的任务并执行某个副作用操作(如打印日志、更新状态等)的场景。

方法签名:

public CompletableFuture<Void> runAfterEither(
	CompletionStage<?> other,
	Runnable action)

- **`other`**:另一个 `CompletionStage`。
- **`action`**:当第一个任务完成时执行的 `Runnable` 操作。
- **返回类型**:返回一个新的 `CompletableFuture<Void>`,表示操作完成。

使用场景:

runAfterEither() 方法适用于当你只关心某个任务完成后执行某些副作用操作,而不需要处理任务的结果时。

示例代码:

@Test  
public void test() {  
    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {  
        try {  
            Thread.sleep(1000);  
        } catch (InterruptedException e) {  
            Thread.currentThread().interrupt();  
        }  
        return 2;  
    });  
  
    CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {  
        try {  
            Thread.sleep(500);  
        } catch (InterruptedException e) {  
            Thread.currentThread().interrupt();  
        }  
        return 3;  
    });  
  
    future1.runAfterEither(future2, () -> System.out.println("第一个完成的任务已经结束"));  
}

分析

  • future1future2 分别执行两个异步任务。
  • runAfterEither() 会在第一个任务完成后执行 Runnable 操作,这里是打印 "第一个完成的任务已经结束"
  • 无论哪个任务先完成,都会触发打印操作,而不关心它们的计算结果。

 

三. acceptEither:消费第一个任务的结果

acceptEither() 方法与 applyToEither() 方法类似,不同之处在于它接受一个 BiConsumer 来消费完成任务的结果,而不是返回一个新的 CompletableFuture。该方法适用于只需要消费结果的场景。

方法签名:

public void acceptEither(CompletionStage<? extends T> other, 
						 Consumer<? super T> action)



- **`other`**:另一个 `CompletionStage`。
- **`action`**:当第一个任务完成时执行的 `Consumer` 操作。
- **返回类型**:该方法没有返回值,它会直接消费任务的结果。

使用场景:
acceptEither() 方法适用于当我们只关心任务的结果并需要消费(如打印、记录日志等)时,但不需要返回任何新的 CompletableFuture

示例代码:

@Test  
public void test2() {  
    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {  
        try {  
            Thread.sleep(1000);  
        } catch (InterruptedException e) {  
            Thread.currentThread().interrupt();  
        }  
        return 2;  
    });  
  
    CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {  
        try {  
            Thread.sleep(500);  
        } catch (InterruptedException e) {  
            Thread.currentThread().interrupt();  
        }  
        return 3;  
    });  
  
    //使用 join() 阻塞直到操作完成  
    future1.acceptEither(future2, (result) -> System.out.println("第一个完成的任务的结果: " + result)).join();  
  
}

**分析**- `future1` 和 `future2` 分别执行异步任务。
- `acceptEither()` 会选择第一个完成的任务,并将其结果传递给 `Consumer` 进行处理。在这里,我们将结果打印出来。
- 输出会是 `"第一个完成的任务的结果: 3"`,因为 `future2` 在500ms时先完成。

在测试代码中,通常会使用 join() 来确保异步任务完成后,主线程再退出,避免出现异步回调没有被执行的情况。

四. 三种接口总结

  • applyToEither():在两个异步任务中选择一个最先完成的任务,并对其结果应用一个函数,返回一个新的 CompletableFuture
  • runAfterEither():在两个任务中选择一个最先完成的任务,不关心任务的结果,只执行一个 Runnable 操作。
  • acceptEither():在两个任务中选择一个最先完成的任务,并对其结果执行一个 Consumer 操作,适用于消费任务的结果。

这三个方法提供了灵活的工具,可以帮助我们在多个并行任务中选择一个最先完成的任务,并根据需求对其结果进行处理或执行副作用操作。掌握这些方法,可以让我们更高效地进行异步编程和任务调度。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用 MSYS2 qemu 尝鲜Arm64架构国产Linux系统

近期&#xff0c;我的师弟咨询我关于Arm64架构的国产CPU国产OS开发工具链问题。他们公司因为接手了一个国企的单子&#xff0c;需要在这类环境下开发程序。说实在的我也没有用过这个平台&#xff0c;但是基于常识&#xff0c;推测只要基于C和Qt&#xff0c;应该问题不大。 1. …

一、html笔记

(一)前端概述 1、定义 前端是Web应用程序的前台部分,运行在PC端、移动端等浏览器上,展现给用户浏览的网页。通过HTML、CSS、JavaScript等技术实现,是用户能够直接看到和操作的界面部分。上网就是下载html文档,浏览器是一个解释器,运行从服务器下载的html文件,解析html、…

9.2k star!PiliPala一个第三方B站客户端!

软件介绍 链接 PiliPala一个在Github上收获9.2k star的开源第三方bilibili客户端&#xff0c;支持安卓和ios端安装使用。应用界面简洁无广、除核心功能外无任何冗余功能和服务&#xff0c;让我们可以尽情的享受内容带给我们的快乐。 基础的功能如登录、点赞收藏、评论、关注、…

嵌入式C语言:大小端详解

目录 一、大小端的概念 1.1. 大端序&#xff08;Big-endian&#xff09; 1.2. 小端序&#xff08;Little-endian&#xff09; 二、大小端与硬件体系的关系 2.1. 大小端与处理器架构 2.2. 大小端与网络协议 2.3. 大小端对硬件设计的影响 三、判断系统的大小端方式 3.1.…

ZZNUOJ(C/C++)基础练习1031——1040(详解版)

1031 : 判断点在第几象限 题目描述 从键盘输入2个整数x、y值&#xff0c;表示平面上一个坐标点&#xff0c;判断该坐标点处于第几象限&#xff0c;并输出相应的结果。 输入 输入x&#xff0c;y值表示一个坐标点。坐标点不会处于x轴和y轴上&#xff0c;也不会在原点。 输出 输出…

8.[前端开发-CSS]Day08-图形-字体-字体图标-元素定位

一、额外知识补充 1 border图形 边框的形状 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport"…

Qt事件处理:理解处理器、过滤器与事件系统

1. 事件 事件 是一个描述应用程序中、发生的某些事情的对象。 在 Qt 中&#xff0c;所有事件都继承自 QEvent &#xff0c;并且每个事件都有特定的标识符&#xff0c;如&#xff1a;Qt::MouseButtonPress 代表鼠标按下事件。 每个事件对象包含该事件的所有相关信息&#xff…

大白话讲清楚embedding原理

Embedding&#xff08;嵌入&#xff09;是一种将高维数据&#xff08;如单词、句子、图像等&#xff09;映射到低维连续向量的技术&#xff0c;其核心目的是通过向量表示捕捉数据之间的语义或特征关系。以下从原理、方法和应用三个方面详细解释Embedding的工作原理。 一、Embe…

git笔记-简单入门

git笔记 git是一个分布式版本控制系统&#xff0c;它的优点有哪些呢&#xff1f;分为以下几个部分 与集中式的版本控制系统比起来&#xff0c;不用担心单点故障问题&#xff0c;只需要互相同步一下进度即可。支持离线编辑&#xff0c;每一个人都有一个完整的版本库。跨平台支持…

利用metaGPT多智能体框架实现智能体-1

1.metaGPT简介 MetaGPT 是一个基于大语言模型&#xff08;如 GPT-4&#xff09;的多智能体协作框架&#xff0c;旨在通过模拟人类团队的工作模式&#xff0c;让多个 AI 智能体分工合作&#xff0c;共同完成复杂的任务。它通过赋予不同智能体特定的角色&#xff08;如产品经理、…

当WebGIS遇到智慧文旅-以长沙市不绕路旅游攻略为例

目录 前言 一、旅游数据组织 1、旅游景点信息 2、路线时间推荐 二、WebGIS可视化实现 1、态势标绘实现 2、相关位置展示 三、成果展示 1、第一天旅游路线 2、第二天旅游路线 3、第三天旅游路线 4、交通、订票、住宿指南 四、总结 前言 随着信息技术的飞速发展&…

windows10 配置使用json server作为图片服务器

步骤1&#xff1a;在vs code中安装json server, npm i -g json-server 注意&#xff1a;需要安装对应版本的json server&#xff0c;不然可能会报错&#xff0c;比如&#xff1a; npm i -g json-server 0.16.3 步骤2&#xff1a;出现如下报错&#xff1a; json-server 不是…

洛谷 P1164 小A点菜 C语言

P1164 小A点菜 - 洛谷 | 计算机科学教育新生态 题目背景 uim 神犇拿到了 uoi 的 ra&#xff08;镭牌&#xff09;后&#xff0c;立刻拉着基友小 A 到了一家……餐馆&#xff0c;很低端的那种。 uim 指着墙上的价目表&#xff08;太低级了没有菜单&#xff09;&#xff0c;说&…

向上调整算法(详解)c++

算法流程&#xff1a; 与⽗结点的权值作⽐较&#xff0c;如果⽐它⼤&#xff0c;就与⽗亲交换&#xff1b; 交换完之后&#xff0c;重复 1 操作&#xff0c;直到⽐⽗亲⼩&#xff0c;或者换到根节点的位置 这里为什么插入85完后合法&#xff1f; 我们插入一个85&#xff0c;…

50. 正点原子官方系统镜像烧写实验

一、Windows下使用OTG烧写系统 1、在Windos使用NXP提供的mfgtool来向开发烧写系统。需要用先将开发板的USB_OTG接口连接到电脑上。 Mfgtool工具是向板子先下载一个Linux系统&#xff0c;然后通过这个系统来完成烧写工作。 切记&#xff01;使用OTG烧写的时候要先把SD卡拔出来&…

AI智能化模型助力太阳能光伏板自动巡检运维,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建无人机航拍场景下太阳能光伏板污损缺陷智能检测识别系统

随着全球科技和能源领域的飞速发展&#xff0c;清洁新能源&#xff0c;尤其是太阳能&#xff0c;正以前所未有的速度融入我们的日常生活。太阳能光伏板作为转换太阳能为电能的关键设备&#xff0c;其普及程度日益提高&#xff0c;从偏远乡村到繁华都市&#xff0c;无处不在地展…

深度学习 DAY3:NLP发展史

NLP发展史 NLP发展脉络简要梳理如下&#xff1a; (远古模型&#xff0c;上图没有但也可以算NLP&#xff09; 1940 - BOW&#xff08;无序统计模型&#xff09; 1950 - n-gram&#xff08;基于词序的模型&#xff09; (近代模型&#xff09; 2001 - Neural language models&am…

FireFox | Google Chrome | Microsoft Edge 禁用更新 final版

之前的方式要么失效&#xff0c;要么对设备有要求&#xff0c;这次梳理一下对设备、环境几乎没有要求的通用方式&#xff0c;universal & final 版。 1.Firefox 方式 FireFox火狐浏览器企业策略禁止更新_火狐浏览器禁止更新-CSDN博客 这应该是目前最好用的方式。火狐也…

【问题记录】DeepSeek本地部署遇到问题

详细的部署过程以及原理&#xff0c;各位大佬已经解释的很详细了&#xff0c;这里不重复只是记录过程中遇到的一个问题。 本地部署 DeepSeek-R1 模型全攻略 - 王浩宇的博客) 问题详情 Error: Post "http://127.0.0.1:11434/api/show": read tcp 127.0.0.1:57395-&g…

【react-redux】react-redux中的 useDispatch和useSelector的使用与原理解析

一、useSelector 首先&#xff0c;useSelector的作用是获取redux store中的数据。 下面就是源码&#xff0c;感觉它的定义就是首先是createSelectorHook这个方法先获得到redux的上下文对象。 然后从上下文对象中获取store数据。然后从store中得到选择的数据。 2、useDispatc…