分享一个JDK批量异步任务工具CompletionService,超好用

JAVA-批量异步任务实现 什么是 ?定义: 是 Java 8 引入的异步编程工具,用于表示一个可能在未来完成的异步计算的结果。它支持链式操作、组合多个异步任务、异常处理和回调机制。核心机制:异步执行:通过 或 启动异步任务(默认使用 的公共线程池)。链式处理:通过 、、 等方法串联任务。组合任务:通过 、 合并多个任务的结果。技术核心场景并行处理:同时执行多个耗时任务(如调用多个外部 API、查询多个数据库)。结果聚合:在所有任务完成后合并结果。响应式编程:构建非阻塞、异步的流水线操作。优点缺点场景:并行查询多个数据库,合并结 阅读详情

如何优化一个查询各个价格接口的代码?若使用“ThreadPoolExecutor+Future”,可能优化如下:

三个线程异步执行查询价格,通过三次调用Future的get()方法获取结果,之后将查询结果保存在MySQL。

 

若获取price1耗时很长,那么即便获取price2耗时短,也无法让保存price2的操作先执行,因为主线程都阻塞在 f1.get()。这种问题如何解决呢?

加个阻塞队列! 获取到price1、2、3都进入阻塞队列,然后在主线程消费阻塞队列,就能保证先获取到的价格先保存:

 

CompletionService实现查询价格

实际开发推荐CompletionService,不但能帮你解决先获取到的价格先保存,还能精简代码。

CompletionService内部维护了一个阻塞队列,当任务执行结束就把任务的执行结果入队,但CompletionService是把任务执行结果的Future对象入队,而上面demo是把任务最终执行结果入队。

创建CompletionService

CompletionService接口的实现类是ExecutorCompletionService,这个实现类的构造方法有两个,分别是:

  • ExecutorCompletionService(Executor executor);

 

  • ExecutorCompletionService(Executor executor, BlockingQueue<Future<V>> completionQueue)

 

这俩构造器都需要传入一个线程池,若不指定completionQueue,默认使用无界LinkedBlockingQueue。任务执行结果的Future对象就是加入到completionQueue中。

学长~你直接给我写段代码解释清楚点呗 ~

让我们试着利用CompletionService实现高性能的查询房价系统。 之后通过CompletionService#submit()提交三个询价操作,这三个询价操作将会被CompletionService异步执行。

最后CompletionService#take()获取一个Future对象(加入到阻塞队列的是任务执行结果的Future对象),调用Future#get()就能返回执行结果。

 

CompletionService接口

CompletionService接口提供的方法

 

submit()相关的方法有两个:

  • 一个方法参数是Callable<V> task
  • 一个方法有两个参数,分别是Runnable task和V result,该方法类似于ThreadPoolExecutor的 <T> Future<T> submit(Runnable task, T result) ,

CompletionService实现Dubbo#Forking Cluster

Dubbo中有一种叫做Forking的集群模式,这种集群模式下,支持并行调用多个查询服务,只要有一个成功返回结果,整个服务即可返回。例如你需要提供一个地址转坐标的服务,为了保证该服务的高可用和性能,可并行调用3个地图服务商的API,然后只要有1个正确返回了结果r,那么地址转坐标这个服务就可以直接返回r了。这种集群模式可以容忍2个地图服务商服务异常,但缺点是消耗的资源偏多。

geocoder(addr) {
   // 并行执行以下3个查询服务, 
   r1=geocoderByS1(addr);
   r2=geocoderByS2(addr);
   r3=geocoderByS3(addr);
   // 只要r1,r2,r3有一个返回
   // 则返回
   return r1|r2|r3;
 }

利用CompletionService可快速实现 Forking 这种集群模式,比如下面示例代码。 首先创建一个线程池executor 、一个CompletionService对象cs和一个Future<Integer>类型的列表 futures,每次通过调用CompletionService的submit()方法提交一个异步任务,会返回一个Future对象,把这些Future对象保存在列表futures中。通过调用 cs.take().get(),我们能够拿到最快返回的任务执行结果,只要我们拿到一个正确返回的结果,就可以取消所有任务并且返回最终结果了。

// 创建线程池
 ExecutorService executor =
   Executors.newFixedThreadPool(3);
 // 创建CompletionService
 CompletionService<Integer> cs =
   new ExecutorCompletionService<>(executor);
 // 用于保存Future对象
 List<Future<Integer>> futures =
   new ArrayList<>(3);
 // 提交异步任务,并保存future到futures 
 futures.add(
   cs.submit(()->geocoderByS1()));
 futures.add(
   cs.submit(()->geocoderByS2()));
 futures.add(
   cs.submit(()->geocoderByS3()));
 // 获取最快返回的任务执行结果
 Integer r = 0;
 try {
   // 只要有一个成功返回,则break
   for (int i = 0; i < 3; ++i) {
     r = cs.take().get();
     // 简单地通过判空来检查是否成功返回
     if (r != null) {
       break;
     }
   }
 } finally {
   // 取消所有任务
   for(Future<Integer> f : futures)
     f.cancel(true);
 }
 // 返回结果
 return r;

总结

当需要批量提交异步任务,推荐CompletionService。CompletionService将线程池Executor和阻塞队列融合,让批量异步任务管理更简单。

CompletionService能让异步任务的执行结果有序化,先执行完的先进入阻塞队列,利用该特性,可以轻松实现后续处理的有序性,避免无谓等待,同时还可以快速实现诸如Forking Cluster这样的需求。

CompletionService的实现类ExecutorCompletionService,需要你自己创建线程池,虽看上去有些啰嗦,但好处是你可以让多个ExecutorCompletionService的线程池隔离,这种隔离性能避免几个特别耗时的任务拖垮整个应用的风险。

Grey Hack v0.7.3618 保姆级教程:手把手教你用metaxploit.so写一个自动提权脚本 本文详细介绍了如何在Grey Hack v0.7.3618中使用metaxploit.so库编写自动化提权脚本。从环境准备到核心功能解析,再到漏洞利用链构建和权限提升的智能处理,手把手教你掌握游戏中的高级黑客技巧。通过多库联合利用和错误处理优化,提升脚本的效率和成功率。 阅读详情

相关推荐

Framelet Transform

需要定义 Framelet 的基函数。Framelet 基函数可以是通过组合不同的小波函数生成的。# 这里可以定义 Framelet 基函数,例如一些小波基函数的线性组合# 这是一个示例函数,具体实现需要根据具体的 Framelet 设计# 示例:正弦函数。

qq_33009429的博客 1212

Java并发操作并获取任务结果工具类

import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; /** * 并发操作工具类 * * * 核心和最大池大小 * ThreadPoolExecutor将根据 corePoolSize(请参阅getCorePoolSize )和getCorePoolSize (

qq_26493481的博客 358

用Unity Wheel Collider做坦克转向?3步实现履带式载具物理效果

本文详细解析了如何利用Unity的Wheel Collider组件实现履带式载具的差速转向物理效果。通过思维转换、场景搭建和核心代码实现三步,将Wheel Collider从模拟轮式车辆转向改造为控制履带扭矩差的系统,并深入探讨了参数调试与真实感提升的方法,帮助开发者打造物理反馈扎实的坦克或特种车辆模拟。

weixin_29009971的博客 225

教校花学妹JDK批量异步任务最强工具CompletionService

如何优化一个询价应用的核心代码?如果采用“ThreadPoolExecutor+Future”的方案,你的优化结果很可能是下面示例代码这样:用三个线程异步执行询价,通过三次调用Future的get()方法获取询价结果,之后将询价结果保存在数据库中。 // 创建线程池 ExecutorService executor = Executors.newFixedThreadPool(3); // 异步向电商S1询价 Future f1 = executor.submit( ()->getPriceByS1(

JavaEdge全是干货的技术号 2216

保姆级教程:用Protege 5.5.0从零构建你的第一个知识图谱(附实战案例文件)

本文提供了一份详细的Protege 5.5.0使用指南,从零开始构建知识图谱。涵盖环境配置、本体结构设计、实例填充到可视化展示的全流程,特别适合初学者快速掌握知识建模技术。通过实战案例演示,帮助读者理解如何定义类、属性及建立实例关系,是学习知识图谱构建的实用教程。

weixin_42548816的博客 555

STM32H745xI双核芯片SMPS/LDO配置误区:从复位失败到精准排查的实战复盘

本文详细分析了STM32H745xI双核芯片在SMPS/LDO配置中的常见误区,特别是复位失败问题的排查过程。通过对比参考板与故障板的波形数据,揭示了电感选型不当导致的电源稳定性问题,并提供了硬件设计检查清单和调试技巧,帮助开发者避免类似陷阱。

weixin_42531588的博客 265

java一个“批处理”工具类

前言 我们在日常的开发中有时候会面临着大批量的执行某个方法的时候,我们有时候会需要把一个大的任务拆分成小的任务执行,这个时候我提供的工具就派上用场了 下面的工具支持同步的拆分执行和通过线程池异步执行. 本工具充分利用了java的泛型和lambda表达式, 可以执行各种批量的业务逻辑,但是使用异步方式的时候要注意线程安全的问题。 使用方式 同步方法的使用方式 这个是批量的从数据库中查询出数据的使用方式 List<DialBookDO> dialPlanPhoneBookDOList = Batc

之城的专栏 891

展会客流统计的客流统计系统,WiFi客流每时每客

一般展会的举行时间都在3-7天之间,展会作为市场部门一项重要工作,一直以来没有一项有效的工具能够提供数据支持。 展会最重要的是通过活动和产品来吸引参展者的参观,如何统计展会期间的客流量呢?如何通过将数据转化成为活动数据的支撑呢? 目前成熟的解决方案有,视频客流统计、WiFi客流统计、红外线客流统计等方式。由于展会通常的时间都比较短,视频、红外线客流统计采购及安装价格都比较高,需

isentech的博客 3998

简单好用的批量执行工具-Java

解决问题 批量执行任务时,总是需要关注许多的边界问题 Example 比如需要打印1-100的数字,每一批10个 List<Integer> workList = new ArrayList<>(); for (int i = 0; i < 100; i++) { workList.add(i + 1); } BatchUtil.process(10, workList, (list) -> { System.out.printl

渣渣瑞 6052

手眼标定(EyeToHand)推导

Base为基坐标系(B),工具末端坐标系(T),标定板为Mark坐标系(M),相机坐标系(C)对于每两个姿态都存在上式,组成一个AX=XB的矩阵方程,X为。此时转换成AX=0的问题,单纯用SVD求奇异解便可得到。相机坐标系到Base基坐标系下的转换关系。已知标定板与机械臂末端的相对位置固定不变,,即。带入(2)式求,至此求解出需要的手眼矩阵。在眼在手外的时候,其实是要求解。

stevenreally6的博客 1144

【机器人技术基础】MATLAB Robotics Toolbox PUMA560 运动学正逆解

机器人技术基础实验2报告 1. 实验目的和要求 2. 实验手段 2.1 实验原理 2.2 函数详解 3. 实验主要内容 4. 实验结果和分析 4.1 正运动学求解 例1 例2 4.2 逆运动学求解 例1 例2 1. 实验目的和要求 掌握常见形式的机器人的D-H坐标系建立方法、运动学建模; 正逆运动学分析与求解; 使用Robotics Toolbox对直角坐标机器人、圆柱坐标机器人、球坐标机器人、PUMA560其中之一建立运动学模型,正逆求解和仿真。 2. 实验手段 2.1

【人工智障 | 计算鸡视觉 | 机器孩】 1万+

java 使用多线程处理业务逻辑和批量处理数据

将数据分批可以使用guava里面的工具类,pom中引入。

liangshitian的博客 2360

AI原生SaaS应用的自动化运维体系构建

随着ChatGPT掀起的AI原生应用浪潮,越来越多SaaS(软件即服务)产品开始以"AI优先"的方式设计——从用户交互到核心功能,都深度依赖机器学习模型(如推荐算法、智能客服)、实时数据流(如用户行为分析)和弹性算力(如大模型推理)。这类应用的运维需求与传统SaaS完全不同:传统运维像"修水管",哪里漏了补哪里;AI原生运维则像"照顾会成长的宠物",需要实时感知模型状态、数据变化和流量波动,主动调整资源。

AI天才研究院 1082

聊聊 Java 8异步并发利器:CompletionService

大家好,我是不才陈某~CompletionService的实现目标是任务先完成可优先获取到,即结果按照完成先后顺序排序。今天深入聊一下CompletionService,往期也分享了一些 Java 的一些好用工具,如下:20 个实例玩转 Java 8 StreamJava 8 的 Optional是个好东西6 款 Java 8 自带工具,轻松分析定位 JVM 问题!Java 8 的异步编程利器 C...

码猿技术专栏 473

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

摘录他人博客内容

为什么80%的码农都做不了架构师?>>> ...

weixin_34183910的博客 154

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

学习笔记:java并发编程学习之初识Concurrent

一、初识Concurrent 第一次看见concurrent的使用是在同事写的一个抽取系统代码里,当时这部分代码没有完成,有许多的问题,另一个同事接手了这部分代码的功能开发,由于他没有多线程开发的经验,所以我就一起帮着分析。最开始看到这个时很烦燥啊,因为自己接触java时间很短,连synchronized都不知道怎么用呢,突然发现有这么个复杂的东西。当时就只好开始学习吧,毕竟是使用嘛,第一目的就...

weixin_33772645的博客 114

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

多线程+List分段处理批量数据

多线程+List分段处理批量数据

qq_38042187的博客 3752

Java使用线程池批量处理数据操作

1.如何保证数据按顺序批量处理 2.如何保证数据全部处理完统一返回 3.如何保证是多任务异步操作 4.如何提高运行效率,减少运行时间

weixin_44030476的博客 6552

多线程任务批处理通用工具类

使用线程池批量处理任务,当任务处理完毕之后,方法继续向下走。

weixin_51977686的博客 471

java多线程异步处理批量数据

java多线程异步操作批量数据

Jzq0006的博客 3900

(二十二)CompletionService:如何批量执行异步任务?

在《23 | Future:如何用多线程实现最优的“烧水泡茶”程序?》的最后,我给你留了道思考题,如何优化一个询价应用的核心代码?如果采用“ThreadPoolExecutor+Future”的方案,你的优化结果很可能是下面示例代码这样:用三个线程异步执行询价,通过三次调用Future的get()方法获取询价结果,之后将询价结果保存在数据库中。 // 创建线程池 ExecutorService executor = Executors.newFixedThreadPool(3); // 异步向电商S

lss446937072的博客 546

CompletionService: 获取异步任务执行结果

**1、ExecutorService ** 使用Future和Callable可以获取线程池中任务执行的结果,但其获取方式是阻塞的,根据添加到线程池中的线程顺序依次获取,获取不到就阻塞住主线程。 public class AsyncTask { public static void main(String[] args) { ExecutorService executor = Execu...

weixin_43238110的博客 440

Java发起同异步HTTP请求和处理数据

本文探讨了同步与异步的概念差异及其在Java HTTP请求中的应用。通过生活类比(接力跑vs齐跑)和编程实例,阐明了同步需顺序执行而异步可并发处理的本质。文章重点比较了Java中同步与异步HTTP请求的性能差异,测试数据显示异步方式在处理大批量请求时效率显著提升(如10万次请求从17分钟缩短至3分钟)。针对Java8环境,作者推荐使用CompletableFuture实现异步请求,并提供了完整的代码示例,包括请求头设置、时间参数处理和异步任务管理。文末强调异步编程能有效解决高并发场景下的性能瓶颈问题。

weixin_42077074的博客 4677

java批量任务处理框架_Java多线程批量处理、线程池的使用

1、引言在开发中,有时会遇到批量处理的业务。如果单线程处理,速度会非常慢,可能会导致上游超时。这是就需要使用多线程开发。创建线程时,应当使用线程池。一方面避免了处理任务时创建销毁线程开销的代价,另一方面避免了线程数量膨胀导致的过分调度问题,保证了对内核的充分利用。可以使用J.U.C提供的线程池:ThreadPoolExecutor类。在Spring框架中,也可以使用ThreadPoolTaskEx...

weixin_36251916的博客 1825

Java多线程数据库事务提交控制

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一、循环操作的代码 二、使用事务的操作代码 三、尝试多线程进行数据修改 四、为多线程提交添加事务控制 总结 前言 公司业务中遇到一个需求,需要同时修改最多约5万条数据,而且还不支持批量或异步修改操作。循环操作耗时太长,为提高效率我进行了下面这个测试,具体操作如下: 一、循环操作的代码 /*** * 一条一条依次对50000条数据进行更新操作 * ...

JohnChen(Net) 6760

如何批量执行异步任务

先对这里的异步任务做下解释: 这里的意思是,该任务有几种状态,创建,等待,运行,结束;其中等待是因为,该任务要正常运行,需要其他线程(或进程)提供相应的条件(或触发事件),然后才会运行。 针对这种要异步处理(等待)的任务队列管理模式,个人理解有两种处理方法。 第一种: 也是最常规的一种,定义一个队列,创建任务,然后push到队列里面去,每个任务创建之后,(或接到开启命令)启动等待(定时...

干货小抽屉 1350
上一篇: Redis 很屌,不懂使用规范就糟蹋了
下一篇: “算法考核没过,老板找我聊了3个小时”:离职程序员重刷数学题
Javaesandyou
博客等级 码龄5年 742粉丝 563原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值