Java等待异步线程池跑完再执行指定方法的三种方式(condition、CountDownLatch、CyclicBarrier)
Java等待异步线程池跑完再执行指定方法的三种方式(condition、CountDownLatch、CyclicBarrier)
@Async如何使用
使用@Async标注在方法上,可以使该方法异步的调用执行。而所有异步方法的实际执行是交给TaskExecutor的。
1.启动类添加@EnableAsync注解
2. 方法上添加@Async,类上添加@Component
三个异步方法
@Asyncpublic void doTaskTwo( CyclicBarrier barry) throws Exception {System.out.println("开始做任务二");long start = System.currentTimeMillis();Thread.sleep(random.nextInt(3000));long end = System.currentTimeMillis();System.out.println("完成任务二,耗时:" + (end - start) + "毫秒");barry.await();}@Asyncpublic void doTaskThree( CyclicBarrier barry) throws Exception {System.out.println("开始做任务三");long start = System.currentTimeMillis();Thread.sleep(random.nextInt(5000));long end = System.currentTimeMillis();System.out.println("完成任务三,耗时:" + (end - start) + "毫秒");barry.await();}@Override@Asyncpublic void doTask2One(CountDownLatch count) throws Exception {System.out.println("开始做任务1");long start = System.currentTimeMillis();Thread.sleep(random.nextInt(3000));long end = System.currentTimeMillis();System.out.println("完成任务1,耗时:" + (end - start) + "毫秒");count.countDown();}
CyclicBarrier
@GetMapping("/doTask")public void doLogin() throws Exception {// 通过它可以实现让一组线程等待至某个状态之后再全部同时执行//第一个参数,表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。//第二个参数,表示用于在线程到达屏障时,优先执行barrierAction这个Runnable对象,方便处理更复杂的业务场景。CyclicBarrier barry = new CyclicBarrier(3, new Runnable() {@Overridepublic void run() {System.out.println("1111111111111");}});kafkaTopicService.doTaskOne(barry);kafkaTopicService.doTaskTwo(barry);kafkaTopicService.doTaskThree(barry);}
执行结果
开始做任务一
开始做任务二
开始做任务三
完成任务一,耗时:1263毫秒
完成任务二,耗时:2508毫秒
完成任务三,耗时:3753毫秒
1111111111111
注意: 接口响应成功时候 后台逻辑还在走
CyclicBarrier 的使用场景也很丰富。
比如,司令下达命令,要求 10 个士兵一起去完成项任务。
这时就会要求 10 个士兵先集合报到,接着,一起雄赳赳,气昂昂地去执行任务当 10 个士兵把自己手上的任务都执行完了,那么司令才能对外宣布,任务完成
CyclicBarrier 比 CountDownLatch 略微强大一些,它可以接收一个参数作为 barrierAction。
所谓 barrierAction 就是当计数器一次计数完成后,系统会执行的动作。
如下构造函数,其中, parties 表示计数总数,也就是参与的线程总数。
public CyclicBarrier(int parties, Runnable barrierAction)
package com.shockang.study.java.concurrent.aqs;import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;public class CyclicBarrierDemo {public static class Soldier implements Runnable {private String soldier;private final CyclicBarrier cyclic;Soldier(CyclicBarrier cyclic, String soldierName) {this.cyclic = cyclic;this.soldier = soldierName;}public void run() {try {//等待所有士兵到齐 第一次等待cyclic.await();doWork();//等待所有士兵完成工作 第二次等待cyclic.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}}void doWork() {try {Thread.sleep(Math.abs(new Random().nextInt() % 10000));} catch (InterruptedException e) {e.printStackTrace();}System.out.println(soldier + ":任务完成");}}public static class BarrierRun implements Runnable {boolean flag;int N;public BarrierRun(boolean flag, int N) {this.flag = flag;this.N = N;}public void run() {if (flag) {System.out.println("司令:[士兵" + N + "个,任务完成!]");} else {System.out.println("司令:[士兵" + N + "个,集合完毕!]");flag = true;}}}public static void main(String args[]) throws InterruptedException {final int N = 10;Thread[] allSoldier = new Thread[N];boolean flag = false;CyclicBarrier cyclic = new CyclicBarrier(N, new BarrierRun(flag, N));//设置屏障点,主要是为了执行这个方法System.out.println("集合队伍!");for (int i = 0; i < N; ++i) {System.out.println("士兵 " + i + " 报道!");allSoldier[i] = new Thread(new Soldier(cyclic, "士兵 " + i));allSoldier[i].start();}}
}
控制台输出
集合队伍!
士兵 0 报道!
士兵 1 报道!
士兵 2 报道!
士兵 3 报道!
士兵 4 报道!
士兵 5 报道!
士兵 6 报道!
士兵 7 报道!
士兵 8 报道!
士兵 9 报道!
司令:[士兵10个,集合完毕!]
士兵 0:任务完成
士兵 3:任务完成
士兵 6:任务完成
士兵 4:任务完成
士兵 9:任务完成
士兵 8:任务完成
士兵 2:任务完成
士兵 5:任务完成
士兵 7:任务完成
士兵 1:任务完成
司令:[士兵10个,任务完成!]
说明
上述代码第 65 行创建了 CyclicBarrier 实例,并将计数器设置为 10 ,要求在计数器达到指标时,执行第 51 行的 run() 方法。
每一个士兵线程都会执行第 18 行定义的 run() 方法。
在第 24 行,每一个士兵线程都会等待,直到所有的士兵都集合完毕。
集合完毕意味着 CyclicBarrier 的一次计数完成,当再一次调用 CyclicBarrier.await() 方法时,会进行下一次计数。
第 22 行模拟了士兵的任务。
当一个士兵任务执行完,他就会要求 CyclicBarrier 开始下次计数,这次计数主要目的是监控是否所有的士兵都己经完成了任务。
一旦任务全部完成,第 42 行定义的 BarrierRun 就会被调用,打印相关信息。
2、CountDownLatch
@GetMapping("/doTask2")public void doTask2() throws Exception {CountDownLatch count = new CountDownLatch(3);kafkaTopicService.doTask2One(count);kafkaTopicService.doTask2Two(count);kafkaTopicService.doTask2Three(count);count.await();System.out.println("11111111111111111");}
执行结果:
开始做任务1
开始做任务二
开始做任务3
完成任务1,耗时:179毫秒
完成任务3,耗时:1829毫秒
完成任务二,耗时:2376毫秒
11111111111111111
注意: 接口响应成功时候 后台逻辑已经走完
1、juc中condition接口提供的await、signal、signalAll方法,需配合lock
List<Integer> villageList = new ArrayList<>();List<Integer> villageList2 = new ArrayList<>();villageList.add(1);villageList.add(2);villageList.add(3);ExecutorService threadPool = Executors.newFixedThreadPool(2);Lock lock = new ReentrantLock();Condition cond = lock.newCondition();for(int flag = 0;flag<villageList.size();flag++){Integer i = villageList.get(flag);threadPool.execute(() -> {try {villageList2.add(i);} catch (Exception e) {e.printStackTrace();}if(villageList2.size() == villageList.size()){lock.lock();cond.signal();lock.unlock();}});}lock.lock();try {cond.await(5, TimeUnit.SECONDS);lock.unlock();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(villageList2.size());threadPool.shutdown();
}
CountDownLatch和CyclicBarrier的比较
1.CountDownLatch是减计数方式,countDown()方法只参与计数不会阻塞线程,而CyclicBarrier是加计数方式,await()方法参与计数,会阻塞线程。
2.CountDownLatch计数为0无法重置,而CyclicBarrier计数达到初始值,则可以重置,因此CyclicBarrier可以复用。
附:CountDownLatch有发令枪的效果,可以用来并发测试
public class test2 {private final static CountDownLatch CountDownLatch=new CountDownLatch(100);public static void main(String[] args) throws Exception{for (int i=0;i<100;i++){new Thread(() -> {try {CountDownLatch.await();} catch (Exception e) {e.printStackTrace();}getUUID();}).start();CountDownLatch.countDown(); //如果减到0 统一出发,发枪开炮}}public static void getUUID(){UUID uuid= UUID.randomUUID();System.out.println(uuid);}
}
注意事项
-
CountDownLatch 对象的计数器只能减不能增,即一旦计数器为 0,就无法再重新设置为其他值,因此在使用时需要根据实际需要设置初始值。
-
CountDownLatch 的计数器是线程安全的,多个线程可以同时调用 countDown() 方法,而不会产生冲突。
-
如果 CountDownLatch 的计数器已经为 0,再次调用 countDown() 方法也不会产生任何效果。
-
如果在等待过程中,有线程发生异常或被中断,计数器的值可能不会减少到 0,因此在使用时需要根据实际情况进行异常处理。
当worker1线程由于异常没有执行countDown()方法,最后state结果不为0,导致所有线程停在AQS中自旋(死循环)。所以程序无法结束。(如何解决这个问题呢?请看案例二)
// 等待 3 个线程完成任务
if (!latch.await(5, TimeUnit.SECONDS)) {LOGGER.warn("{} time out", worker1.name);
}// 所有线程完成任务后,执行下面的代码
LOGGER.info("all workers have finished their jobs!");
- CountDownLatch 可以与其他同步工具(如 Semaphore、CyclicBarrier)结合使用,实现更复杂的多线程同步。
相关文章:
Java等待异步线程池跑完再执行指定方法的三种方式(condition、CountDownLatch、CyclicBarrier)
Java等待异步线程池跑完再执行指定方法的三种方式(condition、CountDownLatch、CyclicBarrier) Async如何使用 使用Async标注在方法上,可以使该方法异步的调用执行。而所有异步方法的实际执行是交给TaskExecutor的。 1.启动类添加EnableAsync注解 2. 方法上添加A…...
秒杀优化+秒杀安全
1.Redis预减库存 1.OrderServiceImpl.java 问题分析 2.具体实现 SeckillController.java 1.实现InitializingBean接口的afterPropertiesSet方法,在bean初始化之后将库存信息加载到Redis /*** 系统初始化,将秒杀商品库存加载到redis中** throws Excepti…...
48、Flink 的 Data Source API 详解
a)概述 本节将描述 FLIP-27 中引入的新 Source API 的主要接口。 b)Source Source API 是一个工厂模式的接口,用于创建以下组件。 Split EnumeratorSource ReaderSplit SerializerEnumerator Checkpoint Serializer 此外,Sou…...
深入解析Java扩展机制:SPI与Spring.factories
目录 Java SPI概述 1.1 什么是SPI?1.2 SPI的工作原理1.3 SPI的优缺点 SPI的应用 2.1 Java标准库中的SPI应用2.2 自定义SPI示例 Spring.factories概述 3.1 什么是spring.factories?3.2 spring.factories的工作原理3.3 spring.factories的优缺点 spring.f…...
Vue2之模板语法
文章目录 1.模板语法1.1 插值语法{{}}可以写什么1.2 指令语法1.2.1 指令概述1.2.2 v-bind指令1.2.3 v-model指令 1.模板语法 1.1 插值语法{{}}可以写什么 (1)在data中声明的 (2)常量 (3)合法的JavaScript…...
java基础练习题
1、一个".java"源文件中是否可以包括多个类?有什么限制? 可以包含多个类。但是只有一个类可以声明为public,且要求声明为public的类的类名与源文件名相同。 2、java的优势? a、跨平台性 b、安全性高 c、简单性 d、…...
unity中通过实现底层接口实现非按钮(图片)的事件监听
编写监听脚本 PEListenter 继承自MonoBehaviour类,并实现了IPointerDownHandler、IPointerUpHandler和IDragHandler接口,按照需求定义需要接收事件(鼠标按下、抬起、拖拽)的回调函数 //监听类(需要挂载在物体上面&am…...
重庆耶非凡科技有限公司的选品师项目加盟靠谱吗?
在当今电子商务的浪潮中,选品师的角色愈发重要。而重庆耶非凡科技有限公司以其独特的选品师项目,在行业内引起了广泛关注。对于想要加盟该项目的人来说,项目的靠谱性无疑是首要考虑的问题。 首先,我们来看看耶非凡科技有限公司的背…...
《青少年编程与数学》课程方案:4、课程策略
《青少年编程与数学》课程方案:4、课程策略 一、工程师思维二、使命感驱动三、价值观引领四、学习现代化五、工作生活化六、与时代共进 《青少年编程与数学》课程策略强调采用工程师思维,避免重复造轮子,培养使命感,通过探索兴趣、…...
用爬虫实现---模拟填志愿
先来说实现逻辑,首先我要获取到这个网站上所有的信息,那么我们就可以开始对元素进行检查 我们发现他的每一个学校信息都有一个对应的属性,并且是相同的,那么我们就可以遍历这个网页中的所有属性一样的开始爬取 在来分析࿰…...
vscode Run Code输出出现中文乱码情况问题解决方案
主要解决方案是通过修改计算机默认的编码格式,来完成的。 chcp 是 Windows 操作系统中的一个命令,用于显示或设置控制台的代码页(code page)。代码页决定了控制台如何解释和显示字符,特别是非 ASCII 字符(例如 Unicode 字符)。 使用方法 显示当前代码页: 输入 chcp 而…...
代码随想录训练营Day30
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、重新安排行程 前言 提示:这里可以添加本文要记录的大概内容: 今天是跟着代码随想录刷题的第30天,主要是复习了回溯算法…...
Swift 序列(Sequence)排序面面俱到 - 从过去到现在(二)
概览 在上篇 Swift 序列(Sequence)排序面面俱到 - 从过去到现在(一)博文中,我们讨论了 Swift 语言中序列和集合元素排序的一些基本知识,我们还给出了以自定义类型中任意属性排序的“康庄大道”。 不过在实际的撸码场景中,我们往往需要的是“多属性”同时参与到排序的考…...
STM32F103C8T6基于HAL库移植uC/OS-III
文章目录 一、建立STM32CubeMX工程二、移植1、 uC/OS-III源码2、移植过程 三、配置相关代码1、bsp.c和bsp.h2、main.c3、修改启动代码4、修改app_cfg.h文件5、修改includes.h文件6、修改lib_cfg.h文件 四、编译与烧录总结参考资料 学习嵌入式实时操作系统(RTOS&…...
微服务学习Day9-分布式事务Seata
文章目录 分布式事务seata引入理论基础CAP定理BASE理论 初识Seata动手实践XA模式AT模式TCC模式SAGA模式 高可用 分布式事务seata 引入 理论基础 CAP定理 BASE理论 初识Seata 动手实践 XA模式 AT模式 TCC模式 Service Slf4j public class AccountTCCServiceImpl implements A…...
vue用vite配置代理解决跨域问题(target、rewrite和changeOrigin的使用场景)
Vite的target、rewrite和changeOrigin的使用场景 1. target 使用场景:target 属性在 Vite 的 vite.config.ts 或 vite.config.js 文件的 server.proxy 配置中指定,用于设置代理服务器应该将请求转发到的目标地址。这通常是一个后端服务的API接口地址。…...
为什么PPT录制没有声音 电脑ppt录屏没有声音怎么办
一、为什么PPT录制没有声音 1.软件问题 我们下载软件的时候可能遇到软件损坏的问题,导致录制没有声音,但其他功能还是可以使用的。我建议使用PPT的隐藏功能,下载插件,在PPT界面的加载项选项卡中就能使用。我推荐一款可以解决录屏…...
JDBC学习笔记(三)高级篇
一、JDBC 优化及工具类封装 1.1 现有问题 1.2 JDBC 工具类封装 V1.0 resources/db.properties配置文件: driverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql:///atguigu usernameroot password123456 initialSize10 maxActive20 工具类代码: p…...
c++编译器在什么情况下会提供类的默认构造函数等,与析构函数
我们都知道,在 c 里,编写的简单类,若没有自己编写构造析构函数与 copy 构造函数 与 赋值运算符函数,那么编译器会提供这些函数,并实现简单的语义,比如成员赋值。看 源码时,出现了下图类似的情形…...
SpringBoot3整合Mybatis-Plus3.5.5出现的问题
主要是由于 mybatis-plus 中 mybatis 的整合包版本不够导致的 排除 mybatis-plus 中自带的 mybatis 整合包,单独引入即可 java.lang.IllegalArgumentException: Invalid value type for attribute factoryBeanObjectType: java.lang.Stringat org.springframework.…...
服务器数据恢复—强制上线raid5阵列离线硬盘导致raid不可用的数据恢复案例
服务器数据恢复环境: 某品牌2850服务器中有一组由6块SCSI硬盘组建的raid5磁盘阵列,linux操作系统ext3文件系统。 服务器故障: 服务器运行过程中突然瘫痪。服务器管理员检查阵列后发现raid5阵列中有两块硬盘离线,将其中一块硬盘进行…...
初入阿里云,上手走一波
初入阿里云,上手走一波 一阶:ECSMysqlDMS安装Mysql初始化MysqlMysql操作DMS管理Mysql 二阶:ECSOSS远程连接ECSOSS控制台其他图片服务 三阶:更多搭配操作 可以说个人在日常使用过程中,操作最多的阿里云产品就是阿里云服…...
[C++] 小游戏 斗破苍穹 2.2.1至2.11.5所有版本(中) zty出品
目录 2.8.2 2.9.1 2.10.1 2.10.2 2.10.3 2.10.4 2.10.5 2.8.2 #include<stdio.h> #include<iostream> #include<ctime> #include<bits/stdc.h> #include<time.h> //suiji #include<windows.h> //SLEEP函数 using namespace std; st…...
Javaweb---HTTPS
题记 为了保护数据的隐私性我们引入了HTTPS 加密的方式都有那些呢? 1.对称加密: 加密和解密使用的密钥是同一个密钥 2.非对称加密:有两个密钥(一对),分为公钥和私钥(公钥是公开的,私钥是要藏好的) HTTPS的工作过程(旨在对body和header进行加密) 1.对称加密 上述引出的…...
[已解决]ESP32-C3上传程序成功但没有反应的问题
ESP32-C3上传程序成功但没有反应的问题 ESP32-C3是一款功能强大的微控制器,常用于物联网(IoT)应用的开发和原型设计。然而,有时候在上传程序成功后,设备却没有任何反应,十分让人费解。通过各种尝试已解决这…...
使用 OCLint进行静态代码分析:一个完整的配置示例
文章目录 0. 概述1. 安装 oclint2. oclint配置文件3. 脚本详解3.1 禁用的规则列表3.2 需要启用的规则代码风格代码复杂性命名规范性能安全性其他 4. 检测执行1. 使用 CMake 生成 compile_commands.json2. 运行 Oclint 0. 概述 OCLint是一个静态代码分析工具,通过词…...
【Linux】线程的互斥
一、进程线程间的互斥相关的背景概念 临界资源:多线程执行流共享的资源就叫做临界资源临界区:每一个线程内部,访问临界资源的代码,就叫做临界区互斥:任何时刻,互斥保证有且只有一个执行流进入临界区&#…...
electron如何让你窗口总是显示在最前面【mac解决全屏窗口alwaysOnTop参数不起作用】
你创建了一个使用Electron框架的应用程序,并希望它在以下情况下始终保持可见: 在切换工作区(桌面)时可见在其他应用程序之上显示当其他应用程序全屏显示时,它也显示在顶部当Keynote处于演示模式时,它也能显示在顶部 特别是当Keynote处于演示模式时,要实现这一点比较困难…...
XR和Steam VR项目合并问题
最近有一个项目是用Steam VR开发的,里面部分场景是用VRTK框架做的,还有一部分是用SteamVR SDK自带的Player预制直接开发的。 这样本身没有问题,因为最终都是通过SteamVR SDK处理的,VRTK也管理好了SteamVR的逻辑,并且支…...
uni-app:利用Vue的原型对象Vue.prototype设置全局方法及其引用
一、在main.js中设置方法checkPermission绑定到Vue.prototype 核心代码 Vue.prototype.$checkPermission function(username) {console.log(Checking permission for:, username); }; 完整代码 import App from ./App// 添加 checkPermission 方法到 Vue.prototype 上,检查…...
大连网站排名优化价格/网上教育培训机构哪家好
包括像我这样的初学者的文件操作在内的完整步骤假设您有一个.jsonl文件,如:{"reviewerID": "A2IBPI20UZIR0U", "asin": "1384719342", "reviewerName": "cassandra tu \"Yeah, well, thats…...
信阳专业做网站公司/怎么做百度关键词排名
一、赛题解读 1、赛题分析 赛题任务需要对添加了水印的图像,将水印擦除掉,还原原本的图的样子(图1)。 与手写文字擦除任务(图2)一个比较大的区别是:水印占据面积很大,因此对水印擦除后,还需要对被擦除的区域进行一个填…...
徐州专业网站建设公司/营销型网站外包
前言递归是一种非常重要的算法思想,无论你是前端开发,还是后端开发,都需要掌握它。在日常工作中,统计文件夹大小,解析xml文件等等,都需要用到递归算法。它太基础太重要了,这也是为什么面试的时候…...
思茅网站建设/数字营销成功案例
1:知识点1:在定义一个类时,我们可以显式或隐式的定义在此类型的对象拷贝、赋值、移动、销毁是做什么,主要通过五种特殊的成员函数来完成这些操作:拷贝构造函数、拷贝复制运算符、移动构造函数、移动复制运算符。析构函数 知识点2:拷贝和移动构造函数定义了当用同类型的一…...
临沂网站建设公司全国/惠州网站seo
有的时候,大家可能会遇到这种需求:显示某个物体的线框,就像汽车设计图纸(CAD之类的)那样。例如下面这种效果: 效果1: 效果2: 用shader就可以解决这个问题。甚至可以不写代码&#x…...
江西疫情最新通报今天/点石关键词排名优化软件
在使用vue做开发的时候,我们有时会遇到需要保留组件状态的情况,防止页面重新绘制,这时候就需要使用keep-alive组件,该组件属于vue的内置组件,同transition一样,他本身不会渲染。 当组件在 <keep-alive&g…...