Java8实战-总结50
Java8实战-总结50
- CompletableFuture:组合式异步编程
- 对多个异步任务进行流水线操作
- 对 Future 和 CompletableFuture 的回顾
- 响应 CompletableFuture 的 completion 事件
- 对最佳价格查询器应用的优化
CompletableFuture:组合式异步编程
对多个异步任务进行流水线操作
对 Future 和 CompletableFuture 的回顾
CompletableFuture利用Lambda表达式以声明式的API提供了一种机制,能够用最有效的方式,非常容易地将多个以同步或异步方式执行复杂操作的任务结合到一起。为了更直观地感受一下使用CompletableFuture在代码可读性上带来的巨大提升,可以尝试仅使用Java 7中提供的特性,重新实现前面代码的功能。下面的代码展示了如何实现这一效果(利用Java 7的方法合并两个Future对象):
ExecutorService executor = Executors.newCachedThreadPool(); //创建一个ExecutorService将任务提交到线程池//创建一个查询欧元到美元转换汇率的Future
final Future<Double> futureRate = executor.submit(new Callable<Double>() {public Double call() { return exchangeService.getRate(Money.EUR, Money.USD); }}); Future<Double> futurePriceInUSD = executor.submit(new Callable<Double>() {public Double call() {double priceInEUR = shop.getPrice(product); //在第二个 Future中查询指定商店中特定商品的价格return priceInEUR * futureRate.get(); //在查找价格操作的同一个Future中,将价格和汇率做乘法计算出汇后价格}});
在上面的代码中,通过向执行器提交一个Callable对象的方式创建了第一个Future对象,向外部服务查询欧元和美元之间的转换汇率。紧接着,你创建了第二个Future对象,查询指定商店中特定商品的欧元价格。最终,用与之前代码一样的方式,在同一个Future中通过查询商店得到的欧元商品价格乘以汇率得到了最终的价格。注意,之前的代码中中如果使用thenCombineAsync,不使用thenCombine,像上面的代码一样,采用第三个Future单独进行商品价格和汇率的乘法运算,效果是几乎相同的。这两种实现看起来没太大区别,原因是你只对两个Future进行了合并。通过这两段代码,我们能看到创建流水线对同步和异步操作进行混合操作有多么简单,随着处理任务和需要合并结果数目的增加,这种声明式程序设计的优势也愈发明显。
你的“最佳价格查询器”应用基本已经完成,不过还缺失了一些元素。你会希望尽快将不同商店中的商品价格呈现给你的用户(这是车辆保险或者机票比价网站的典型需求),而不是像你之前那样,等所有的数据都完备之后再呈现。接下来的一节,你会了解如何通过响应CompletableFuture的completion事件实现这一功能(与此相反,“调用get或者join方法只会造成阻塞,直到CompletableFuture完成才能继续往下运行)。
响应 CompletableFuture 的 completion 事件
下面这部分的所有示例代码都是通过在响应之前添加1秒钟的等待延迟模拟方法的远程调用。毫无疑问,现实世界中,你的应用访问各个远程服务时很可能遭遇无法预知的延迟,触发的原因多种多样,从服务器的负荷到网络的延迟,有些甚至是源于远程服务如何评估你应用的商业价值,即可能相对于其他的应用,你的应用每次查询的消耗时间更长。
由于这些原因,你希望购买的商品在某些商店的查询速度要比另一些商店更快。以下面的代码清单为例,使用randomDelay方法取代原来的固定延迟。下面的代码是一个模拟生成0.5秒至2.5秒随机延迟的方法:
private static final Random random = new Random();
public static void randomDelay() {int delay = 500 + random.nextInt(2000); try { Thread.sleep(delay); } catch (InterruptedException e) { throw new RuntimeException(e); }
}
目前为止,你实现的findPrices方法只有在取得所有商店的返回值时才显示商品的价格。而你希望的效果是,只要有商店返回商品价格就在第一时间显示返回值,不再等待那些还未返回的商店(有些甚至会发生超时)。你如何实现这种更进一步的改进要求呢?
对最佳价格查询器应用的优化
要避免的首要问题是,等待创建一个包含了所有价格的List创建完成。你应该做的是直接处理CompletableFuture流,这样每个CompletableFuture都在为某个商店执行必要的操作。为了实现这一目标,在下面的代码清单中,会对前面代码实现的第一部分进行重构,实现findPricesStream方法来生成一个由CompletableFuture构成的流。重构findPrices方法返回一个由Future构成的流:
public Stream<CompletableFuture<String>> findPricesStream(String product) {return shops.stream().map(shop -> CompletableFuture.supplyAsync( () -> shop.getPrice(product), executor)).map(future -> future.thenApply(Quote::parse)).map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote), executor)));
}
现在,你为findPricesStream方法返回的Stream添加了第四个map操作,在此之前,你已经在该方法内部调用了三次 map 。这个新添加的操作其实很简单,只是在每个CompletableFuture上注册一个操作,该操作会在CompletableFuture完成执行后使用它的返回值。Java 8的CompletableFuture通过thenAccept方法提供了这一功能,它接收CompletableFuture执行完毕后的返回值做参数。在这里的例子中,该值是由Discount服务返回的字符串值,它包含了提供请求商品的商店名称及折扣价格,你想要做的操作也很简单,只是将结果打印输出:
findPricesStream("myPhone").map(f -> f.thenAccept(System.out::println));
注意,和之前的thenCompose和thenCombine方法一样,thenAccept方法也提供了一个异步版本,名为thenAcceptAsync。异步版本的方法会对处理结果的消费者进行调度,从线程池中选择一个新的线程继续执行,不再由同一个线程完成CompletableFuture的所有任务。因为你想要避免不必要的上下文切换,更重要的是你希望避免在等待线程上浪费时间,尽快响应CompletableFuture的completion事件,所以这里没有采用异步版本。由 于thenAccept方法已经定义了如何处理CompletableFuture返回的结果,一旦CompletableFuture计算得到结果,它就返回一个CompletableFuture<Void>。所以,map操作返回的是一个Stream<CompletableFuture<Void>>。对这个<CompletableFuture<Void>>对象,你能做的事非常有限,只能等待其运行结束,不过这也是你所期望的。你还希望能给最慢的商店一些机会,让它有机会打印输出返回的价格。为了实现这一目的,你可以把构成Stream的所有CompletableFuture<Void>对象放到一个数组中,等待所有的任务执行完成,代码如下所示(响应CompletableFuture的completion事件):
CompletableFuture[] futures = findPricesStream("myPhone").map(f -> f.thenAccept(System.out::println)).toArray(size -> new CompletableFuture[size]);
CompletableFuture.allOf(futures).join();
allOf工厂方法接收一个由CompletableFuture构成的数组,数组中的所有CompletableFuture对象执行完成之后,它返回一个CompletableFuture<Void>对象。这意味着,如果你需要等待最初Stream中的所有 CompletableFuture对象执行完毕,对 allOf方法返回的CompletableFuture执行join操作是个不错的主意。这个方法对“最佳价格查询器”应用也是有用的,因为你的用户可能会困惑是否后面还有一些价格没有返回,使用这个方法,你可以在执行完毕之后打印输出一条消息“All shops returned results or timed out”。
然而在另一些场景中,你可能希望只要CompletableFuture对象数组中有任何一个执行完毕就不再等待,比如,你正在查询两个汇率服务器,任何一个返回了结果都能满足你的需求。在这种情况下,你可以使用一个类似的工厂方法anyOf。该方法接收一个CompletableFuture对象构成的数组,返回由第一个执行完毕的CompletableFuture对象的返回值构成的CompletableFuture<Object>。
相关文章:
Java8实战-总结50
Java8实战-总结50 CompletableFuture:组合式异步编程对多个异步任务进行流水线操作对 Future 和 CompletableFuture 的回顾 响应 CompletableFuture 的 completion 事件对最佳价格查询器应用的优化 CompletableFuture:组合式异步编程 对多个异步任务进行…...
kicad源代码研究:参照Candence实现工程管理
创建工程: 创建工程和打开工程触发事件: KICAD_MANAGER_ACTIONS::newProjectKICAD_MANAGER_ACTIONS::openProjectnewProject和OpenProject事件响应具体实现,在KICAD_MANAGER_CONTROL类中实现: Go( &KICAD_MANAGER_CONTROL::…...
Asp.net core WebApi 配置自定义swaggerUI和中文注释,Jwt Bearer配置
1.创建asp.net core webApi项目 默认会引入swagger的Nuget包 <PackageReference Include"Swashbuckle.AspNetCore" Version"6.2.3" />2.配置基本信息和中文注释(默认是没有中文注释的) 2.1创建一个新的controller using Micr…...
DNS 查询结果逐行解释
文章目录 FlagsADDITIONALANSWER SECTIONQuery timeSERVERWHENDNS PortAuthoritative answer权威DNS服务器Non-authoritative answer推荐阅读 DNS查询后,查询结果一般如下: mirrorUbuntu22:~$ dig www.baidu.com; <<>> DiG 9.18.12-0ubuntu0…...
ArcGIS制作广场游客聚集状态及密度图
文章目录 一、加载实验数据二、平均最近邻法介绍1. 平均最近邻工具2. 广场游客聚集状态3. 结果分析三、游客密度制图一、加载实验数据 二、平均最近邻法介绍 1. 平均最近邻工具 “平均最近邻”工具将返回五个值:“平均观测距离”、“预期平均距离”、“最近邻指数”、z 得分和…...
同旺科技 USB TO SPI / I2C --- 调试W5500_TCP Client接收数据
所需设备: 内附链接 1、USB转SPI_I2C适配器(专业版); 首先,连接W5500模块与同旺科技USB TO SPI / I2C适配器,如下图: 发送数据6个字节的数据:0x11,0x22,0x33,0x44,0x55,0x66 在专业版调试软件中编辑指令,…...
MQ - KAFKA 高级篇
kafak是一个分布式流处理平台,提供消息持久化,基于发布-订阅的方式的消息中间件,同时通过消费端配置相同的groupId支持点对点通信。 ##适用场景: 构造实时流数据管道,用于系统或应用之间可靠的消息传输.数据采集及处理,例如连接到一个数据库系统,捕捉表…...
如何快速查找最后(最右侧)隐藏列
实例需求:定位工作表中的最后(最右侧)隐藏列,处理其中的数据。 通常思路是从工作表最后列开始,倒序检查每个列,直到找到隐藏列或者检查完毕(无隐藏列)。 Sub LastColumn()Dim visR…...
精密制造ERP系统包含哪些模块?精密制造ERP软件是做什么的
不同种类的精密制造成品有区别化的制造工序、工艺流转、品质标准、生产成本、营销策略等,而多工厂、多仓库、多车间、多部门协同问题却是不少精密制造企业遇到的管理难题。 有些产品结构较为复杂,制造工序繁多,关联业务多,传统的…...
TypeScript 的高级技巧
1 — 高级类型(Advanced Types) 使用 TypeScript 的高级类型,如映射类型和条件类型,可以基于现有类型构建新类型。通过使用这些类型,您可以在强类型系统中更改和操作类型,从而使您的代码具有更大的灵活性和…...
TiDB 7.x 源码编译之 TiDB Server 篇,及新特性详解
本文将介绍如何编译 TiDB Server 源码。以及阐释 TiDB Server 7.x 的部分新特性。 TiDB v7.5.0 LTS 计划于 2023 年 11 月正式 Release,目前代码虽未冻结,但已经可以看到 Alpha 版本的 Code 了,本文代码将以 v7.5.0-alpha 为基准。 TiDB Se…...
Hadoop实验putty文件
🔥博客主页: A_SHOWY🎥系列专栏:力扣刷题总结录 数据结构 云计算 数字图像处理 很多朋友反馈做hadoop实验中的putty找不到Connection-SSH-Auth路径下找不到Private key for authentication私有密钥,无法将转…...
研发人员绩效考核难题及解决措施
研发部门是技术型企业的核心人员,研发人员的设计贯穿着产品实现过程包括后续的持续改进。倘若研发人员的设计源头得以保障,那么后续工作包括研发人员的绩效考核,相对简单。接下来华恒智信便根据多年来从事的人力资源相关的服务经验为您对于研…...
Inference with C# BERT NLP Deep Learning and ONNX Runtime
目录 效果 测试一 测试二 测试三 模型信息 项目 代码 下载 Inference with C# BERT NLP Deep Learning and ONNX Runtime 效果 测试一 Context :Bob is walking through the woods collecting blueberries and strawberries to make a pie. Question …...
6、原型模式(Prototype Pattern,不常用)
原型模式指通过调用原型实例的Clone方法或其他手段来创建对象。 原型模式属于创建型设计模式,它以当前对象为原型(蓝本)来创建另一个新的对象,而无须知道创建的细节。原型模式在Java中通常使用Clone技术实现,在JavaSc…...
图像万物分割——Segment Anything算法解析与模型推理
一、概述 在视觉任务中,图像分割任务是一个很广泛的领域,应用于交互式分割,边缘检测,超像素化,感兴趣目标生成,前景分割,语义分割,实例分割,泛视分割等。 交互式分割&am…...
Redis实战篇笔记(最终篇)
Redis实战篇笔记(七) 文章目录 Redis实战篇笔记(七)前言达人探店发布和查看探店笔记点赞点赞排行榜 好友关注关注和取关共同关注关注推送关注推荐的实现 总结 前言 本系列文章是Redis实战篇笔记的最后一篇,那么到这里…...
游戏配置表的导入使用
游戏配置表是游戏策划的标配,如下图: 那么程序怎么把这张配置表导入使用? 1.首先,利用命令行把Excel格式的文件转化成Json格式: json-excel\json-excel json Tables\ Data\copy Data\CharacterDefine.txt ..\Clien…...
❀dialog命令运用于linux❀
目录 ❀dialog命令运用于linux❀ msgbox部件(消息框) yesno部件(yesno框) inputbox部件(输入文本框) textbox部件(文本框) menu部件(菜单框) fselect部…...
【算法】蓝桥杯2013国C 横向打印二叉树 题解
文章目录 题目链接题目描述输入格式输出格式样例自己的样例输入自己的样例输出 思路整体思路存储二叉搜索树中序遍历并存储计算目标数的行号dfs遍历并写入数组初始化和处理输入输出初始化处理输入处理输出 完整的代码如下 结束语更新初始化的修改存储二叉搜索树的修改中序遍历和…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
