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.…...

深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...

沙箱虚拟化技术虚拟机容器之间的关系详解
问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西,但是如果把三者放在一起,它们之间到底什么关系?又有什么联系呢?我不是很明白!!! 就比如说: 沙箱&#…...

使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...
前端高频面试题2:浏览器/计算机网络
本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...
webpack面试题
面试题:webpack介绍和简单使用 一、webpack(模块化打包工具)1. webpack是把项目当作一个整体,通过给定的一个主文件,webpack将从这个主文件开始找到你项目当中的所有依赖文件,使用loaders来处理它们&#x…...