当前位置: 首页 > news >正文

【同步工具类:CyclicBarrier】

同步工具类:CyclicBarrier

  • 介绍
  • 源码分析
    • CyclicBarrier 基于ReetrantLock + Condition实现。
    • 构造函数
    • await() 函数
  • 业务场景
    • 方案一:
      • 代码实现
      • 测试截图
    • 方案二
      • 代码实现
      • 测试打印
  • 总结

介绍

官方介绍:
一种同步辅助工具,允许一组线程都等待对方到达共同的障碍点。CyclicBarrier在涉及固定大小的线程组的程序中非常有用,这些线程组偶尔必须彼此等待。该屏障被称为循环屏障,因为它可以在释放等待线程后重新使用。
CyclicBarrier支持可选的Runnable命令,该命令在参与方中的最后一个线程到达后,但在释放任何线程之前,在每个障碍点运行一次。此屏障动作对于在任何一方继续之前更新共享状态都很有用。
通俗理解:
它可以协同多个线程,让多个线程在这个栅栏前等待,直到所有线程都达到了这个栅栏时,再一起继续执行后面的动作.
举个例子,你和朋友约定在公交站汇合,去公园玩。这个公交站相当于栅栏。只有你们都到了公交站,才一起去公园。

源码分析

CyclicBarrier 基于ReetrantLock + Condition实现。

    /** The lock for guarding barrier entry *///用于线程之间互相唤醒private final ReentrantLock lock = new ReentrantLock();/** Condition to wait on until tripped */private final Condition trip = lock.newCondition();//总线程数private final int parties;

构造函数

可以看到,不仅可以传入 参与方的总数量(即 parties)。还可以传入一个回调函数,当所有的线程被唤醒时,barrierAction 被执行,该参数可以为空。

    /*** Creates a new {@code CyclicBarrier} that will trip when the* given number of parties (threads) are waiting upon it, and which* will execute the given barrier action when the barrier is tripped,* performed by the last thread entering the barrier.** @param parties the number of threads that must invoke {@link #await}*        before the barrier is tripped* @param barrierAction the command to execute when the barrier is*        tripped, or {@code null} if there is no action* @throws IllegalArgumentException if {@code parties} is less than 1*/public CyclicBarrier(int parties, Runnable barrierAction) {if (parties <= 0) throw new IllegalArgumentException();this.parties = parties;this.count = parties;this.barrierCommand = barrierAction;}

await() 函数

1.CyclicBarrier 是可以被重用的。
2.CyclicBarrier 会响应中断,N 个线程还没有到齐,如果有线程收到了中断信号,所有阻塞的线程也会被唤醒。也就是 breakBarrier函数。然后count 被重置为初始值(parties),重新开始
3.构造函数传入的回调函数,barrierAction 只会被最后一个线程执行一次。

 public int await() throws InterruptedException, BrokenBarrierException {try {return dowait(false, 0L);} catch (TimeoutException toe) {throw new Error(toe); // cannot happen}}
    /*** Main barrier code, covering the various policies.*/private int dowait(boolean timed, long nanos)throws InterruptedException, BrokenBarrierException,TimeoutException {final ReentrantLock lock = this.lock;lock.lock();try {final Generation g = generation;if (g.broken)throw new BrokenBarrierException();if (Thread.interrupted()) {  //响应中断breakBarrier();  //唤醒所有阻塞的线程throw new InterruptedException();}int index = --count;  //每个线程调用一次await(). count 减一,当count==0时,则唤醒其他的所有线程if (index == 0) {  // trippedboolean ranAction = false;try {final Runnable command = barrierCommand;if (command != null)// 一起唤醒之和,如果回调函数不为空,还需要执行回调函数command.run();ranAction = true;nextGeneration();//唤醒其他所有线程,并将count值复原。//用于下一次的CyclicBarrier.这是可以复用的原因return 0;} finally {if (!ranAction)breakBarrier();}}// loop until tripped, broken, interrupted, or timed out//当count>0,说明 人没有到齐,需要阻塞自己for (;;) {try {if (!timed)trip.await();//当阻塞自己的时候,await方法会释放锁,这样其他线程调用await方法时会执行--countelse if (nanos > 0L)nanos = trip.awaitNanos(nanos);} catch (InterruptedException ie) {//响应中断,如果有线程收到了中断信号,所有的阻塞线程也会被唤醒。if (g == generation && ! g.broken) {breakBarrier();throw ie;} else {// We're about to finish waiting even if we had not// been interrupted, so this interrupt is deemed to// "belong" to subsequent execution.//如果不是响应的中断,说明是被 sigalAll唤醒。则自己唤醒Thread.currentThread().interrupt();}}if (g.broken)throw new BrokenBarrierException();if (g != generation)//从阻塞中被唤醒,然后返回return index;if (timed && nanos <= 0L) {breakBarrier();throw new TimeoutException();}}} finally {lock.unlock();}}
     private void nextGeneration() {// signal completion of last generation// 唤醒所有阻塞的线程trip.signalAll();// set up next generation// 设置初始值,开始下一个轮回count = parties;generation = new Generation();}

业务场景

10 个求职者一起来公司应聘,招聘方式为笔试和面试。首先,需要等10个人到期后,开始笔试,笔试结束之后,再一起参加面试。把10个人看作10个线程。如图所示:
在这里插入图片描述

方案一:

采用一个CyclicBarrier.重复实现两次等待

代码实现

class Solver {public static void main(String[] args) {CyclicBarrier barrier=new CyclicBarrier(10);for (int i=0;i<10;i++){//开启10个线程模拟10个求职者new Thread(new JobHunt(barrier)).start();}}
}class JobHunt implements Runnable {private CyclicBarrier cyclicBarrier;public JobHunt(CyclicBarrier cyclicBarrier) {this.cyclicBarrier = cyclicBarrier;}@Overridepublic void run() {//赶来公司路上doOnTheWay();//到公司后,看人是否到齐,如果没有到齐,就阻塞,// 到齐了就开始笔试try {System.out.println(Thread.currentThread().getName()+" 已经来公司了...");cyclicBarrier.await();doWriteExam();System.out.println(Thread.currentThread().getName()+" 笔试做完了....");cyclicBarrier.await();doInterview();System.out.println(Thread.currentThread().getName()+"  面试完啦.....");} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}}/*** 模拟在路上方法*/public void doOnTheWay(){doCostTime(2000);}/*** 模拟笔试过程*/public void doWriteExam(){doCostTime(3000);}/*** 模拟面试过程*/public void doInterview(){doCostTime(5000);}private void doCostTime(int time){Random random=new Random();try {//随机休眠时间int count=random.nextInt(time);// System.out.println(count);Thread.sleep(count);} catch (InterruptedException e) {e.printStackTrace();}}}

测试截图

从截图中我们可以看出,CyclicBarrier 实现了大家一起等待,直至人到齐了再去一起做笔试或者面试。
在这里插入图片描述

方案二

由于两次等待结束后,打印的消息不一样。所以我们采用两个 CyclicBarrier。分别传入不同的 barrierAction,来实现自定义的 等待结束后的打印事件。

代码实现

class Solver {public static void main(String[] args) {//将笔试等待的回调函数传入CyclicBarrier barrierOnWriteExam=new CyclicBarrier(10,new BarrierActionOnWriteExam());//将面试等待的回调函数传入CyclicBarrier barrierOnInterview=new CyclicBarrier(10,new BarrierActionOnInterview());for (int i=0;i<10;i++){//开启10个线程模拟10个求职者new Thread(new JobHunt(barrierOnWriteExam,barrierOnInterview)).start();}}
}class JobHunt implements Runnable {private CyclicBarrier cyclicBarrierOnWriteExam;private CyclicBarrier cyclicBarrierOnInterview;public JobHunt(CyclicBarrier cyclicBarrierOnWriteExam,CyclicBarrier cyclicBarrierOnInterview) {this.cyclicBarrierOnWriteExam = cyclicBarrierOnWriteExam;this.cyclicBarrierOnInterview=  cyclicBarrierOnInterview;}@Overridepublic void run() {//赶来公司路上doOnTheWay();//到公司后,看人是否到齐,如果没有到齐,就阻塞,// 到齐了就开始笔试try {System.out.println(Thread.currentThread().getName()+" 已经来公司了...");cyclicBarrierOnWriteExam.await();doWriteExam();System.out.println(Thread.currentThread().getName()+" 笔试做完了....");cyclicBarrierOnInterview.await();doInterview();System.out.println(Thread.currentThread().getName()+"  面试完啦.....");} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}}/*** 模拟在路上方法*/public void doOnTheWay(){doCostTime(2000);}/*** 模拟笔试过程*/public void doWriteExam(){doCostTime(3000);}/*** 模拟面试过程*/public void doInterview(){doCostTime(5000);}private void doCostTime(int time){Random random=new Random();try {//随机休眠时间int count=random.nextInt(time);// System.out.println(count);Thread.sleep(count);} catch (InterruptedException e) {e.printStackTrace();}}}class BarrierActionOnWriteExam implements Runnable{@Overridepublic void run() {//自定义等待完成后的回调函数System.out.println("大家人到齐了,开始笔试吧");}}class BarrierActionOnInterview implements Runnable{@Overridepublic void run() {//自定义等待完成后的回调函数System.out.println("大家人到齐了,开始面试吧");}
}

测试打印

通过打印结果可以看到,首先是能正确实现效果。其次 是通过传入 回调事件参数给 CyclicBarrier,可以很方便实现 自己的业务逻辑。
在这里插入图片描述

总结

虽然 CountDownLatch 和CyclicBarrier 都能实现多个线程一起等待然后一起做某些事情。
CountDownLatch 更多的是 一个主线程等待 分支线程完成。然后主线程去做其他事情。
CyclicBarrier 是 大家分别做某些事情,等每个人都做完后,大家再一起去做另外一件事情。
并且两者实现的 原理完全不同。
希望通过本文大家能对 CyclicBarrier 有个更加理性的认识。多敲敲小demo。看能否有优化的地方。这样才能更好的理解。
CountDownLatch 学习的地址:
https://blog.csdn.net/echohuangshihuxue/article/details/129280219

相关文章:

【同步工具类:CyclicBarrier】

同步工具类:CyclicBarrier介绍源码分析CyclicBarrier 基于ReetrantLock Condition实现。构造函数await() 函数业务场景方案一:代码实现测试截图方案二代码实现测试打印总结介绍 官方介绍: 一种同步辅助工具&#xff0c;允许一组线程都等待对方到达共同的障碍点。CyclicBarrie…...

Android 12.0 Settings 去掉打开开发者模式和USB调试模式的广播

1.概述 在12.0的系统产品rom定制化开发中,在系统Settings的开发者模式中,打开开发者模式和usb调试模式都会发出开发者模式改变广播和usb调试模式改变广播, 项目开发功能需要要求去掉这两个广播以免影响其他功能,所以就要看哪里发出广播来屏蔽掉就可以了,这样就可以去掉开发…...

OSI七层网络模型和TCP/IP四层网络模型的异同

文章目录前言一、什么是OSI&#xff1f;二、什么是TCP/IP四层模型&#xff1f;三、OSI七层网络模型和TCP/IP四层网络模型的关系&#xff1a;四、 OSI七层和TCP/IP的区别&#xff1a;前言 本节系统总结&#xff1a; 一、什么是OSI&#xff1f;二、什么是TCP/IP四层模型&#xf…...

接口测试必备技能 - 加密和签名

1、什么是加密以及解密&#xff1f; 加密&#xff1a;在网络上传输的原始数据&#xff08;明文&#xff09;经过加密后形成&#xff08;密文&#xff09;传输&#xff0c;防止被窃取。 解密&#xff1a;将加密还原成原始数据 2、加密方式分类&#xff1f; 对称式加密&#xf…...

JVM虚拟机概述(1)

1.JVM概述 1.1为什么要学习JVM 通过学习JVM ( java Virtual Machine )可以帮助我们理解java程序运行的过程&#xff0c;了解虚拟机中各种机制的实现原理。为后期写出优质的代码做好准备&#xff0c;为向更高的层次提升打好基础。 1.2虚拟机 虚拟机的本质就是在windows中&…...

学习.NET MAUI Blazor(七)、实现一个真正的ChatGPT聊天应用

今天在新闻上看到一条消息&#xff0c;OpenAI已经开放了ChatGPT的接口&#xff0c;也就是GPT-3.5&#xff0c;对比原来的GPT-3&#xff0c;增加了gpt-3.5-turbo、gpt-3.5-turbo-0301两个模型。 gpt-3.5-turbo&#xff1a;使用最新的GPT-3.5模型&#xff0c;并针对聊天进行了优…...

Django框架学习

文章目录Django框架项目开发1. 创建项目2. 项目目录结构3. 视图函数&#xff08;view&#xff09;4. 路由配置url5. HTTP请求6. HTTP响应 - 状态吗7. GET方式传参8. POST传递参数模板Templates1. 通过 loader 获取模板,通过HttpResponse进行响应2. 使用 render() 直接加载并响应…...

JavaSE21-集合1-set

文章目录一、集合概念二、set集合1、set集合的特点2、HashSet2.1 特点2.2 创建对象2.3 常用方法2.4 遍历2.4.1 foreach遍历2.4.2 使用迭代器遍历2.4.3 转换为数组遍历一、集合概念 集合就是用于存储多个数据的容器。相对于具有相同功能的数组来说&#xff0c;集合的长度可变会…...

Web版和客户端哪种SQL工具更好?ChatGPT有话要说

2023年年初公司发布了一款Web版SQL工具&#xff0c;短期内就赢得了众多用户的喜爱和下载。不过&#xff0c;也有SQL用户在评论区中提出自己的观点&#xff0c;认为Web版工具都不可靠&#xff0c;甚至看见Web版工具就劝返… … 工具Web化逐渐成为一种趋势&#xff0c;比如&…...

从客户端的角度来看移动端IM即时通讯的消息可靠性和送达机制

如何确保IM 不丢消息是个相对复杂的话题&#xff0c;从客户端发送数据到服务器&#xff0c;再从服务器抵达目标客户端&#xff0c;最终在 UI 成功展示&#xff0c;其间涉及的环节很多&#xff0c;这里只取其中一环「接收端如何确保消息不丢失」来探讨&#xff0c;粗略聊下我接触…...

2023年java春招面试题及答案

2023年java春招面试题1、下面有关jdbc statement的说法错误的是&#xff1f;2、下面有关JVM内存&#xff0c;说法错误的是&#xff1f;3、下面有关servlet service描述错误的是&#xff1f;4、下面有关servlet和cgi的描述&#xff0c;说法错误的是&#xff1f;5、下面有关SPRIN…...

Django学习——基础篇(上)

一、Django的安装 pip install djangopython目录下出现两个文件 djando-admin.exe django django-admin.exe django 二、创建项目 1.命令行&#xff08;终端&#xff09; 1.打开终端 winR 输入cmd 2.进入项目目录 3.执行命令创建项目 2.Pycharm 两种方法对比 1.命令行创…...

研报精选230302

目录 【个股230302华西证券_比亚迪】系列点评五十四&#xff1a;迪“王”需求向上 出口“海”阔天空【个股230302华西证券_华利集团】下游去库存背景下承压&#xff0c;毛利率保持稳健【个股230302开源证券_恒顺醋业】公司信息更新报告&#xff1a;四季度业绩承压&#xff0c;期…...

Unity心得

- 将结果与因子颠倒的函数Mathf.InverseLerp非常实用 - at 10 meters, you want volume 1 - at 20 meters, you want volume 0 - volume InvLerp( 20, 10, distance ) - 显示HideFlags为Hide类型的物体 Resources .FindObjectsOf…...

TryHackMe-Binex

Binex 枚举计算机并获取交互式 shell。利用 SUID 位文件&#xff0c;使用 GNU 调试器利用缓冲区溢出并通过 PATH 操作获得根访问权限。 端口扫描 循例 nmap SMB枚举 题目给了提示&#xff1a;Hint 1: RID range 1000-1003 Hint 2: The longest username has the unsecure pa…...

外贸人如何写出优秀的开发信?附详细思路

如何写出优秀的开发信&#xff1f;最近做出口生意的客户都在抱怨&#xff0c;开发信的回复率越来越低&#xff0c;其实原因有很多&#xff0c;有时候并非自己的能力实在很欠缺。原因总结如图&#xff1a;第一&#xff1a;市场不景气这个就是就属于客观因素了&#xff0c;这也许…...

python自学之《21天学通Python》(18)——第21章 案例2 Python搞定大数据

“大数据&#xff08;Big Data&#xff09;”这个术语最早期的引用可追溯到apache org的开源项目Nutch。当时&#xff0c;大数据用来描述为更新网络搜索索引需要同时进行批量处理或分析的大量数据集。随着谷歌MapReduce和GoogleFileSystem &#xff08;GFS&#xff09;的发布&a…...

面试问题【数据库】

数据库数据库的三范式是什么drop、delete、truncate 分别在什么场景之下使用char 和 varchar 的区别是什么数据库的乐观锁和悲观锁是什么SQL 约束有哪几种mysql 的内连接、左连接、右连接有什么区别MyIASM和Innodb两种引擎所使用的索引的数据结构是什么mysql 有关权限的表都有哪…...

Allegro如何输出钻孔表操作指导

Allegro如何输出钻孔表操作指导 用Allegro做PCB设计的时候,需要输出钻孔表格,用于生产加工,如下图 如何输出钻孔表,具体操作如下 点击Manufacture点击NC...

消息队列 面试题 整理

消息队列 为什么要使用消息队列&#xff1f; 异步解耦&#xff1a;关注的是通知而非处理。 流量削峰&#xff1a;将短时间内高并发的请求持久化&#xff0c;然后逐步处理&#xff0c;削平高峰期的请求。 日志收集&#xff1a; 事务最终一致性 系统间的消息通信方式&#xff…...

【Java】对象比较大小

在Java中经常会涉及到对象数组的排序问题&#xff0c;那么就涉及到对象之间的比较问题。Java实现对象排序的方式有两种&#xff1a; 自然排序&#xff1a;java.lang.Comparable定制排序&#xff1a;java.util.Comparator 规则&#xff1a;需要我们自定义根据对象的某个或某些属…...

发票自动OCR识别并录入模板 3分钟免费配置

要问整个公司里和数据打交道最多的职能&#xff0c;非财务莫属了吧。除了每天要处理大量财务数据外&#xff0c;还有发票录入的工作让财务陷入“易燃易爆炸”的工作状态。发票报销看似简单&#xff0c;但发票的类型有很多种&#xff0c;每种发票需要录入的信息也有差别。再加上…...

Dubbo 配置说明

dubbo:scan:base-packages: com.ut.msdasw.services.appservice //这个会扫描该包下得全部接口protocol: //这个主要是配置传输的协议和端口&#xff0c;只是一个协议name: dubbo port: 30032registry: //这里是服务注册中心的地址address: spring-cloud://localhost consum…...

英飞凌TCxxx实战系列01_Alarm处理

目录 1.概述2. Alarm内部处理2.1关联的寄存器2.2 Alarm设置case3. SMU外部处理3.1 关联的寄存器4. WDT Alarm的特殊处理4.1 看门狗超时测试4.2 RecoveryTimer相关的Alarm1.概述 当MCU运行出现问题,如MCU温度过高、过低,看门狗超时等会触发一个Alarm,当SMU收到Alarm信号后,…...

飞桨全量支持业内AI科学计算工具——DeepXDE!

AI技术在跨学科融合创新方面扮演着日益重要的角色&#xff0c;特别是在Al for Science领域&#xff0c;AI技术的发展为跨学科、跨领域的融合创新带来了巨大的机会。AI已成为一个关键的研究工具&#xff0c;改变了基础科学的研究范式。依托AI技术开发的科学计算工具&#xff0c;…...

【c++基础】

C基础入门统一初始化输入输出输入输出符输入字符串const与指针c和c中const的区别const与指针的关系常变量与指针同类型指针赋值的兼容规则引用引用的特点const引用作为形参替换指针其他引用形式引用和指针的区别inline函数缺省参数函数重载判断函数重载的规则名字粉碎C编译时函…...

语音识别技术对比分析

文章目录一、语音识别产品对比二、百度语音识别产品1、套餐及价格&#xff1a;2、官网3、调研结果三、华为语音识别产品四、阿里云语音识别产品1、套餐及价格&#xff1a;2、官网地址3、调研结果五、科大讯飞语音识别产品1、套餐及价格&#xff1a;2、官网3、调研结果六、有道语…...

Idea git 回滚远程仓库版本

目标 回滚远程仓库到特定版本。 将【添加test03】版本回滚到【行为型模式】版本。 回滚前的效果图 步骤 ①复制需要回滚到的版本的版本号 ②右键项目&#xff0c;选择Git-Repository-Reset Head ③Reset Type选择Hard&#xff1b;To Commit填入步骤①复制的版本号&#xff…...

vscode C++配置

program&#xff1a;调试入口文件的地址cwd&#xff1a;程序启动调试的目录miDebuggerPath&#xff1a;调试器的路径launch.json// { // // Use IntelliSense to learn about possible attributes. // // Hover to view descriptions of existing attributes. // /…...

【微电网_储能】基于启发式状态机策略和线性程序策略优化方法的微电网中的储能研究【给定系统约束和定价的情况下】(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密…...

戴尔公司网站建设/seo技巧seo排名优化

本文简单的介绍一下如何安装EOS智能合约开发工具包&#xff08;Contract Development Toolkit&#xff09;&#xff0c;简称CDT&#xff0c;是与智能合约编制相关的工具集合。对于EOSIO初学者来说&#xff0c;可以通过使用CDT来编译智能合约和生成ABI。 从1.3.x开始&#xff0c…...

在线做雅思真题网站/成品视频直播软件推荐哪个好一点

“互联网精神”即&#xff1a;开放、平等、协作、分享。“天下大势&#xff0c;浩浩荡荡&#xff1b;顺之者昌&#xff0c;逆之者亡”开放精神 互联网的特质决定着它既没有时间界限也没有地域界限。通过互联网&#xff0c;它无时无刻、无处不在&#xff0c;不停的帮你的信息进行…...

图书类网站开发的背景/东莞关键词排名快速优化

&#xfeff;&#xfeff;Dubbo是Alibaba开源的分布式服务框架&#xff0c;它最大的特点是按照分层的方式来架构&#xff0c;使用这种方式可以使各个层之间解耦合&#xff08;或者最大限度地松耦合&#xff09;。从服务模型的角度来看&#xff0c;Dubbo采用的是一种非常简单的模…...

工业产品设计工资/永州网站seo

案例&#xff1a;怎么看到电脑隐藏的文件&#xff1f; “有时候我在电脑找不到一些文件&#xff0c;听朋友说这些文夹可能是隐藏的&#xff0c;直接查找是找不到的。那怎么才能看到隐藏的文件呢&#xff1f;电脑怎么看隐藏的文件&#xff1f;有没有小伙伴知道具体的方法。” …...

东莞专业网站推广需要多少钱/宠物美容师宠物美容培训学校

文章目录 diff的基本语法及参数 比较两个文件并排格式输出-u 以合并文件的方式显示不同 补充&#xff1a; 三个文本比较命令&#xff1a; comm: 比较相同的文本&#xff0c;特点是&#xff1a; 如果文本中有空格就无法识别 patch 补丁&#xff1a; 举例&#xff1a; 后记 dif…...

律师资格证报考条件/洛阳seo网络推广

关键字描述&#xff1a;支持 首页 文章 更新 自动 DedeCMS 模块 安装DedeCMS V5.3的使用方法很简单~~~直接用后台的模块安装就可以了。坚决贯彻实施官方的插件模块化&#xff0c;一键安装的理念。当然。模板自己去修改。因为没个站的模板都不同的嘛。呵呵20081230 修改部分提示…...