异步回调模式

异步回调

所谓异步回调,本质上就是多线程中线程的通信,如今很多业务系统中,某个业务或者功能调用多个外部接口,通常这种调用就是异步的调用。如何得到这些异步调用的结果自然也就很重要了。
Callable、Future、FutureTask

public class test implements Callable<Boolean>{public static void main(String[] args) {test a=new test();FutureTask futureTask=new FutureTask<>(a);new Thread(futureTask).start();Object su=null;try {su=futureTask.get();}catch (Exception e){e.printStackTrace();}System.out.println(su);}@Overridepublic Boolean call() throws Exception {return null;}
}

FutureTask和Callable都是泛型类,泛型参数表示返回结果的类型。通过FutureTask获取异步线程的执行结果,但是其调用get()方法获取异步结果时,主线程也会被阻塞。属于异步阻塞模式。异步阻塞模式属于主动模式的异步调用,异步回调属于被动模式的异步调用。Java中回调模式的标准实现类为CompletableFuture。由于此类出现时间比较晚,期间Guava和Netty等都提出了自己的异步回调模式API来使用。这里主要介绍CompletableFuture,其他的有时间后面再学习。

CompletableFuture

在这里插入图片描述
CompletableFuture实现Future和CompletionStage两个接口。此类的实例作为一个异步任务,可以在自己异步执行完成之后触发一些其他的异步任务,从而达到异步回调的效果。主要方法如下所示:

runAsync和supplyAsync创建子任务

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 CompletableFuture<Void> runAsync(Runnable runnable) {return asyncRunStage(asyncPool, runnable);
}
public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor) {return asyncRunStage(screenExecutor(executor), runnable);
}

可以看出runAsync没有返回值,supplyAsync有返回值,此处用supplyAsync举例:

ExecutorService executor= Executors.newFixedThreadPool(10);
CompletableFuture<String> completableFuture= CompletableFuture.supplyAsync(()->{return "你好,周先生";
},executor);
System.out.println(completableFuture.get());//输出你好,周先生
executor.shutdown();

上例中的线程池可以自己构造,如若不指定使用CompletableFuture中默认的线程池ForkJoinPool。
handle()方法统一处理异常和结果

//在执行任务的同一个线程中处理异常和结果
public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn) {return uniHandleStage(null, fn);
}
//可能不在执行任务的同一个线程中处理异常和结果
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn) {return uniHandleStage(asyncPool, fn);
}
//在指定线程池executor中处理异常和结果
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor) {return uniHandleStage(screenExecutor(executor), fn);
}

案例:

CompletableFuture<String> completableFuture= CompletableFuture.supplyAsync(()->{throw new RuntimeException("你好");
});
completableFuture.handle(new BiFunction<String,Throwable,String>(){@Overridepublic String apply(String s, Throwable throwable) {if(throwable==null){System.out.println("mei");;}else {System.out.println("出错了");}return "ok";}
});

异步任务的串行执行

主要方法为以下几种:thenApply()、thenAccept()、thenRun()和 thenCompose()。

thenApply()
此方法实现异步任务的串行化执行,前一个任务结果作为下一个任务的入参。

	后一个任务与前一个任务在同一个线程中执行public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn) {return uniApplyStage(null, fn);}//后一个任务与前一个任务不在同一个线程中执行public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn) {return uniApplyStage(asyncPool, fn);}//后一个任务在指定的executor线程池中执行public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor) {return uniApplyStage(screenExecutor(executor), fn);}

其中泛型参数T:上一个任务所返回结果的类型。泛型参数U:当前任务的返回类型。
案例:

		ExecutorService executor= Executors.newFixedThreadPool(10);CompletableFuture<String> completableFuture= CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread().getId());//12return "你好,周先生";},executor).thenApplyAsync(new Function<String,String>() {@Overridepublic String apply(String s) {System.out.println(Thread.currentThread().getId());//13return "你好,毛先生";}});System.out.println(completableFuture.get());//输出你好,毛先生executor.shutdown();

thenRun()
此方法不关心任务的处理结果。只要前一个任务执行完成,就开始执行后一个串行任务。而且没有返回值。

	//后一个任务与前一个任务在同一个线程中执行public CompletableFuture<Void> thenRun(Runnable action) {return uniRunStage(null, action);}//后一个任务与前一个任务可以不在同一个线程中执行public CompletableFuture<Void> thenRunAsync(Runnable action) {return uniRunStage(asyncPool, action);}//后一个任务在executor线程池中执行public CompletableFuture<Void> thenRunAsync(Runnable action,Executor executor) {return uniRunStage(screenExecutor(executor), action);}

thenAccept()
使用此方法时一个任务可以接收(或消费)前一个任务的处理结果,但是后一个任务没有结果输出。

	//后一个任务与前一个任务在同一个线程中执行public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action) {return biAcceptStage(null, other, action);}//后一个任务与前一个任务不在同一个线程中执行public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action) {return biAcceptStage(asyncPool, other, action);}//后一个任务在指定的executor线程池中执行public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action, Executor executor) {return biAcceptStage(screenExecutor(executor), other, action);}

thenCompose()
对两个任务进行串行的调度操作,第一个任务操作完成时,将其结果作为参数传递给第二个任务。

	//后一个任务与前一个任务在同一个线程中执行public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn) {return uniComposeStage(null, fn);}//后一个任务与前一个任务不在同一个线程中执行public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn) {return uniComposeStage(asyncPool, fn);}//后一个任务在指定的executor线程池中执行public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn,Executor executor) {return uniComposeStage(screenExecutor(executor), fn);}

thenCompose()方法第二个任务的返回值是一个CompletionStage异步实例。

		ExecutorService executor= Executors.newFixedThreadPool(10);CompletableFuture<String> completableFuture= CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread().getId());//12return "你好,周先生";},executor).thenComposeAsync(new Function<String,CompletableFuture<String>>(){@Overridepublic CompletableFuture<String> apply(String s) {return CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread().getId());//12return "你好,毛先生";});}});System.out.println(completableFuture.get());//输出你好,毛先生executor.shutdown();

异步任务的合并执行

主要实现为以下几个方法:thenCombine()、runAfterBoth()、
thenAcceptBoth()。

thenCombine()
thenCombine()会在两个CompletionStage任务都执行完成后,一块来处理两个任务的执行结果。如果要合并多个任务,可以使用allOf()。

	//合并第二步任务的CompletionStage实例,返回第三步任务的CompletionStagepublic <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn) {return biApplyStage(null, other, fn);}//不一定在同一个线程中执行第三步任务的CompletionStage实例public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn) {return biApplyStage(asyncPool, other, fn);}//第三步任务的CompletionStage实例在指定的executor线程池中执行public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn, Executor executor) {return biApplyStage(screenExecutor(executor), other, fn);}

其中泛型参数T:表示第一个任务所返回结果的类型。泛型参数U:表示第二个任务所返回结果的类型。泛型参数V:表示第三个任务所返回结果的类型。
案例:

		CompletableFuture<String> future1 = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread().getId());//12return "你好,周先生";});CompletableFuture<String> future2 = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread().getId());//12return "你好,毛先生";});CompletableFuture<String> future3 = future1.thenCombine(future2, new BiFunction<String, String, String>(){@Overridepublic String apply(String s, String s2) {return s+"-----"+s2;}});String s = future3.get();System.out.println(s);//你好,周先生-----你好,毛先生

而runAfterBoth()方法不关注每一步任务的输入参数和输出参数,thenAcceptBoth()中第三个任务接收第一个和第二个任务的结果,但是不返回结果。

异步任务的选择执行

若异步任务的选择执行不是按照某种条件进行选择的,而按照执行速度进行选择的:前面两并行任务,谁的结果返回速度快,其结果将作为第三步任务的输入。对两个异步任务的选择可以通过CompletionStage接口的applyToEither()、acceptEither()等方法来实现。
applyToEither()

	//和其他任务进行速度比较,最快返回的结果用于执行fn回调函数public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn) {return orApplyStage(null, other, fn);}//和其他任务进行速度比较,最快返回的结果用于执行fn回调函数,不一定在同一个线程中执行fn回调函数public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn) {return orApplyStage(asyncPool, other, fn);}//和其他任务进行速度比较,最快返回的结果用于执行fn回调函数,在指定线程池执行fn回调函数public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn,Executor executor) {return orApplyStage(screenExecutor(executor), other, fn);}

案例:

		CompletableFuture<String> future1 = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread().getId());//12try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}return "你好,周先生";});CompletableFuture<String> future2 = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread().getId());//12return "你好,毛先生";});CompletableFuture<String> future3 = future1.applyToEither(future2, new Function<String, String>(){@Overridepublic String apply(String s) {return s;}});String s = future3.get();System.out.println(s);//你好,毛先生

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

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

相关文章

【EI会议征稿中】第三届网络安全、人工智能与数字经济国际学术会议(CSAIDE 2024)

第三届网络安全、人工智能与数字经济国际学术会议&#xff08;CSAIDE 2024&#xff09; 2024 3rd International Conference on Cyber Security, Artificial Intelligence and Digital Economy 第二届网络安全、人工智能与数字经济国际学术会议&#xff08;CSAIDE 2023&…

Shell数组函数:数组——数组和循环(四)

使用数组统计&#xff0c;用户shell的类型和数量 一、脚本编辑 [root192 ~]# vim shell.sh #!/bin/bash declare -A shells while read ii dotypeecho $ii | awk -F: {print $7}let shells[$type] done < /etc/passwdfor i in ${!shells[]} doecho "$i: ${shells[$i]…

SpringSecurity6 | 自定义登录页面

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; Java从入门到精通 ✨特色专栏&#xf…

SAP UI5 walkthrough step7 JSON Model

这个章节&#xff0c;帮助我们理解MVC架构中的M 我们将会在APP中新增一个输入框&#xff0c;并将输入的值绑定到model&#xff0c;然后将其作为描述&#xff0c;直接显示在输入框的右边 首先修改App.controllers.js webapp/controller/App.controller.js sap.ui.define([&…

JAVA使用POI向doc加入图片

JAVA使用POI向doc加入图片 前言 刚来一个需求需要导出一个word文档&#xff0c;文档内是系统某个界面的各种数据图表&#xff0c;以图片的方式插入后导出。一番查阅资料于是乎着手开始编写简化demo,有关参考poi的文档查阅 Apache POI Word(docx) 入门示例教程 网上大多数是XXX…

电商平台商品销量API接口,30天销量API接口接口超详细接入方案说明

电商平台商品销量API接口的作用主要是帮助开发者获取电商平台上的商品销量信息。通过这个接口&#xff0c;开发者可以在自己的应用或网站中实时获取商品的销量数据&#xff0c;以便进行销售分析、库存管理、市场预测等操作。 具体来说&#xff0c;电商平台商品销量API接口的使…

Unity 下载网络图片的方法,并把图片赋值给UI和物体的方法

Unity 下载网络图片的方法&#xff0c;可使用WWW类或UnityWebRequest类&#xff0c;其中UnityWebRequest是新版的方法。 通常我们下载图片都会转成Texture&#xff0c;然后赋值给UI或者物体。 具体实现方法&#xff1a; using System.Collections; using System.Collections…

3D模型制作木质纹理贴图

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 本文将讲解如何使用GLTF 编辑器 -NSDT 在线材质编辑工具为3D模型设置…

朴素贝叶斯 朴素贝叶斯原理

朴素贝叶斯 朴素贝叶斯原理 判别模型和生成模型 监督学习方法又分生成方法 (Generative approach) 和判别方法 (Discriminative approach)所学到的模型分别称为生成模型 (Generative Model) 和判别模型 (Discriminative Model)。 朴素贝叶斯原理 朴素贝叶斯法是典型的生成学习…

城市生态与交通,数据可视化大屏,PSD源文件(ps大屏设计素材)

用酷炫的大屏展示其城市的生态与交通情况&#xff0c;辅助相关决策。好的大屏组件也可以让设计师的工作更加便捷&#xff0c;使其更高效快速的完成设计任务。现分享城市生态与交通的大屏Photoshop源文件&#xff0c;开箱即用&#xff01;以下为部分截图示意。 若需更多的 智慧…

go sort.Search()

函数 func Search(n int, f func(int) bool) int {} 函数作用 通过二分法查找&#xff0c;找到已经排序好的数组[0,n)中第一个使f为true的索引&#xff0c;如果没有找到返回n 为什么要用二分查找&#xff1f; 因为二分查找相比普通依次遍历而言&#xff0c;速度能有巨幅提升…

OFDM模糊函数仿真

文章目录 前言一、OFDM 信号及模糊函数1、OFDM 信号表达式2、模糊函数表达式 二、MATLAB 仿真1、MATLAB 核心源码2、仿真结果①、OFDM 模糊函数②、OFDM 距离模糊函数③、OFDM 速度模糊函数 前言 本文进行 OFDM 的仿真&#xff0c;首先看一下 OFDM 的模糊函数仿真效果&#xf…

数据库事务:保障数据一致性的基石

目录 1. 什么是数据库事务&#xff1f; 1.1 ACID特性解析 2. 事务的实现与控制 2.1 事务的开始和结束 2.2 事务的隔离级别 3. 并发控制与事务管理 3.1 并发控制的挑战 3.2 锁和并发控制算法 4. 最佳实践与性能优化 4.1 事务的划分 4.2 批处理操作 5. 事务的未来发展…

一:C语言常见概念

一&#xff1a;C语言常见概念 1.认识C语言&#xff1a; ​ C语言是人和计算机交流的语言 ​ C语言是一门面向过程的语言&#xff0c;而C&#xff0c;Java&#xff0c;Python等是一门面向对象的语言 ​ 软件开发&#xff08;项目&#xff09;&#xff1a;面向过程面向对象 …

软件科技成果鉴定测试需提供哪些材料?

为了有效评估科技成果的质量&#xff0c;促进科技理论向实际应用转化&#xff0c;所以需要进行科技成果鉴定测试。申请鉴定的科技成果范围是指列入国家和省、自治区、直辖市以及国务院有关部门科技计划内的应用技术成果&#xff0c;以及少数科技计划外的重大应用技术成果。   …

让聪明的车连接智慧的路,C-V2X开启智慧出行生活

“聪明的车 智慧的路”形容的便是车路协同的智慧交通系统&#xff0c;从具备无钥匙启动&#xff0c;智能辅助驾驶和丰富娱乐影音功能的智能网联汽车&#xff0c;到园区的无人快递配送车&#xff0c;和开放的城市道路上自动驾驶的公交车、出租车&#xff0c;越来越多的车联网应用…

99、NeRF ray space

CG相机模型 在图形学中最常用的相机模型的原理和小孔成像是类似的。 不同之处在于&#xff0c;如上图&#xff0c;小孔成像得到的图像是倒立的&#xff0c;但是我们希望得到的图像是正向的&#xff0c;因此&#xff0c;我们选择小孔前成像。 从 3D 到 2D 的投影&#xff0c;…

成本核算基础知识 – 了解实际成本

原文地址&#xff1a;Basics of Costing – Understanding Actual Cost | SAP Blogs 建议大家打开原文地址查看原文&#xff0c;有些地方专业术语翻译不一定正确。希望搬的这些文章能帮助查资料的大家一个信息&#xff0c;再跳转到原文去看。 一、概述 大家好&#xff0c; …

解释AI决策,这10个强大的 Python 库记得收藏!

本文整理了10个常用于可解释AI的Python库&#xff0c;方便我们更好的理解AI模型的决策。 什么是XAI&#xff1f; XAI&#xff08;Explainable AI&#xff09;的目标是为模型的行为和决策提供合理的解释&#xff0c;这有助于增加信任、提供问责制和模型决策的透明度。XAI 不仅…

C#-快速剖析文件和流,并使用

目录 一、概述 二、文件系统 1、检查驱动器信息 2、Path 3、文件和文件夹 三、流 1、FileStream 2、StreamWriter与StreamReader 3、BinaryWriter与BinaryReader 一、概述 文件&#xff0c;具有永久存储及特定顺序的字节组成的一个有序、具有名称的集合&#xff1b; …