CyclicBarrier使用详解及遇到的坑

        上一篇文章讲的是关于是使用CountDownLatch实现生成年底报告遇到的问题,这个计数器和CyclicBarrier也有类似功能,但是应用场景不同。        

一、应用场景

        CountDownLatch

                有ABCD四个任务,ABC是并行执行,等ABC三个任务都执行完毕,D任务再开始执行。

                比如:年度报告需要从3个维度统计,3个维度都统计好后,再查询上面3个维度数据生成最终报告。那么3个维度就是ABC,最后查询3个维度数据的任务就是D任务。

       

        CyclicBarrier

                跑步比赛:5个运动员参加跑步比赛,等5个人都热身完毕了,5个人才开始同时起跑。

                王者荣耀比赛:5个玩家参加比赛,等5个玩家都加载完毕了,5个人才能开赛进行对局。

二、CyclicBarrier是什么    

        CyclicBarrier是一个同步屏障,它允许多个线程相互等待,直到到达某个公共屏障点,才能继续执行。通常用来实现多个线程在同一个屏障处等待,然后再一起继续执行的操作。

CyclicBarrier也维护了一个类似计数器的变量,通过CyclicBarrier的构造函数指定,需要大于0,否则抛IllegalArgumenException异常。当线程到达屏障位置时,调用await()方法进行阻塞,直到所有线程到达屏障位置时,所有线程才会被释放,而屏障将会被重置为初始值以便下次使用

  

三、常用方法

        

CyclicBarrier(int parties):CyclicBarrier的构造方法,可通过parties参数指定需要到达屏障的线程个数,但是要大于0,否则会抛IllegalArgumentException异常。
 

CyclicBarrier(int parties,Runnable barrierAction):另一个构造方法,parties作用同上,barrierAction表示最后一个到达屏障点的线程要执行的逻辑。
 

int await():表示线程到达屏障点,并等待其它线程到达,返回值表示当前线程在屏障中的位置(第几个到达的)。
 

int await(long timeout,TimeUnit unit):与await()类似,但是设置了超时时间,如果超过指定的时间后,仍然还有线程没有到达屏障点,则等待的线程会被唤醒并执行后续操作。
 

void reset():重置屏障状态,即将屏障计数器重置为初始值。
 

int getParties():获取需要同步的线程数量。

int getNumberWaiting():获取当前正在等待的线程数量。

  • CyclicBarrier的计数器可以重置而CountDownLatch不行,这意味着CyclicBarrier实例可以被重复使用而CountDownLatch只能被使用一次。而这也是循环屏障循环二字的语义所在。CyclicBarrier每调用一次await()方法都将使阻塞的线程数+1,只有阻塞的线程数达到设定值时屏障才会打开,允许阻塞的所有线程继续执行。

  • CyclicBarrier允许用户自定义barrierAction操作,这是个可选操作,可以在创建CyclicBarrier对象时指定

四、写个简单例子

package com.lsl.utills;import java.util.Date;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** 循环栅栏* 模拟赛跑比赛:有5个人参加赛跑比赛,要等5个人都准备就绪后,5个人才能一起跑。*/
public class CyclicBarrierDemo02 {//参赛人数private static int count = 5;private static CyclicBarrier cycl;private static ExecutorService executor = Executors.newFixedThreadPool(10);public static void main(String[] args) {CyclicBarrierDemo02 demo02 = new CyclicBarrierDemo02();String name = "参赛者";demo02.runingTest(name);}public void runingTest(String name ){cycl = new CyclicBarrier(5);for (int i =1;i<=count;i++){String nameNew = name + i;executor.execute(new RuningTask(nameNew,i));}}/*** 赛跑任务*/class RuningTask implements Runnable{private String name;//参赛者姓名private int waitTimes;RuningTask(String name,int waitTimes){this.name = name;this.waitTimes = waitTimes;}@Overridepublic void run() {try {//准备阶段,模拟参赛人员热身准备long sleeps = waitTimes*200;Thread.sleep(sleeps);long st = new Date().getTime();System.err.println("name:" + name + "准备好了,准备了" + sleeps + "毫秒");//栅栏位置cycl.await();
//                cycl.await(2, TimeUnit.SECONDS);//开跑long ed = new Date().getTime();long times = ed-st;System.out.println("name:" + name + ",等待了:" + times + "毫秒,开始起跑了");} catch (Exception e) {e.printStackTrace();}}}
}

运行截图:

五、错误代码示例(失效情况)

package com.lsl.utills;import java.util.Date;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** 循环栅栏* 模拟赛跑比赛:有5个人参加赛跑比赛,要等5个人都准备就绪后,5个人才能一起跑。*/
public class CyclicBarrierDemo01 {//参赛人数private static int count = 5;private  CyclicBarrier cycl;private static ExecutorService executor = Executors.newFixedThreadPool(10);public static void main(String[] args) {for (int i =1;i<=count;i++){String name = "参赛者" + i;CyclicBarrierDemo01 demo01 = new CyclicBarrierDemo01();demo01.runingTest(name,i);}}public void runingTest(String name,int num ){cycl = new CyclicBarrier(5);executor.execute(new RuningTask(name,num));}/*** 赛跑任务*/class RuningTask implements Runnable{private String name;//参赛者姓名private int waitTimes;RuningTask(String name,int waitTimes){this.name = name;this.waitTimes = waitTimes;}@Overridepublic void run() {try {//准备阶段,模拟参赛人员热身准备long sleeps = waitTimes*200;Thread.sleep(sleeps);long st = new Date().getTime();System.err.println("name:" + name + "准备好了,准备了" + sleeps + "毫秒");//栅栏位置int numberWaiting = cycl.getNumberWaiting();System.out.println("numberWaiting=" + numberWaiting);cycl.await();
//                cycl.await(2, TimeUnit.SECONDS);//开跑long ed = new Date().getTime();long times = ed-st;System.out.println("name:" + name + ",等待了:" + times + "毫秒,开始起跑了");} catch (Exception e) {e.printStackTrace();}}}
}

错误运行截图:

从错误运行截图可以看出,一直卡在所有参赛者都准备好阶段,没有一起开跑。

原因是上述代码写的有问题,从打印的numberWaiting=0可以分析出,每个线程使用的CyclicBarrier都不一样,因为private CyclicBarrier cycl;定义成了成员变量。

另外,上述代码中把线程内的cycl.await();改成cycl.await(2, TimeUnit.SECONDS);

运行截图如下:

从上述截图可以看出,如果是cycl.await(2, TimeUnit.SECONDS);   在规定时间内没有到设置的计数值,就会抛出异常。

上面的代码改进下,就是定义成静态变量。保证所有线程都是用的一个CyclicBarrier

代码如下:

package com.lsl.utills;import java.util.Date;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** 循环栅栏* 模拟赛跑比赛:有5个人参加赛跑比赛,要等5个人都准备就绪后,5个人才能一起跑。*/
public class CyclicBarrierDemo01 {//参赛人数private static int count = 5;private  static CyclicBarrier cycl;private static ExecutorService executor = Executors.newFixedThreadPool(10);public static void main(String[] args) {for (int i =1;i<=count;i++){String name = "参赛者" + i;CyclicBarrierDemo01 demo01 = new CyclicBarrierDemo01();demo01.runingTest(name,i);}}public void runingTest(String name,int num ){cycl = new CyclicBarrier(5);executor.execute(new RuningTask(name,num));}/*** 赛跑任务*/class RuningTask implements Runnable{private String name;//参赛者姓名private int waitTimes;RuningTask(String name,int waitTimes){this.name = name;this.waitTimes = waitTimes;}@Overridepublic void run() {try {//准备阶段,模拟参赛人员热身准备long sleeps = waitTimes*200;Thread.sleep(sleeps);long st = new Date().getTime();System.err.println("name:" + name + "准备好了,准备了" + sleeps + "毫秒");//栅栏位置int numberWaiting = cycl.getNumberWaiting();System.out.println("numberWaiting=" + numberWaiting);cycl.await();
//                cycl.await(2, TimeUnit.SECONDS);//开跑long ed = new Date().getTime();long times = ed-st;System.out.println("name:" + name + ",等待了:" + times + "毫秒,开始起跑了");} catch (Exception e) {e.printStackTrace();}}}
}

运行截图如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/467874.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

k8s-service、endpoints、pod之间是怎么进行网络互通的

k8s-service、endpoints、pod之间是怎么进行网络互通的 1、service2、endpoints3、service、endpoints、pod通信图4、不通服务pod内部间访问 1、service 在K8S中&#xff0c;Service是一种抽象&#xff0c;定义了一组Pod的逻辑集合和访问这些Pod的策略。首先&#xff0c;我们需…

资产管理系统:SpringBoot技术实现

企业资产管理系统 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了企业资产管理系统的开发全过程。通过分析企业资产管理系统方面的不足&#xff0c;创建了一个计算机管理企业资产管理系统的方案。文章介绍了企…

I.MX6U 裸机开发5.准备C环境并用C语言控制LED

I.MX6U 裸机开发5.准备C环境并用C语言控制LED 一、C运行环境1. 设置处理器模式2. CPSR 寄存器CPSR 寄存器结构模式位MRS 指令MSR 指令 3. 设置SP指针设置 SP 指针示例 保存和恢复 SP 指针示例 4. 跳转到C语言 二、程序编写1. 启动文件 start.S2. main.h 定义寄存器3. 主程序mai…

c++设计模式demo

模式设计原则 依赖倒置原则 ⾼层模块不应该依赖低层模块&#xff0c;⼆者都应该依赖抽象 &#xff1b; 抽象不应该依赖具体实现&#xff0c;具体实现应该依赖于抽象&#xff1b; ⾃动驾驶系统公司是⾼层&#xff0c;汽⻋⽣产⼚商为低层&#xff0c;它们不应该互相依赖&#x…

【go从零单排】泛型(Generics)、链表

&#x1f308;Don’t worry , just coding! 内耗与overthinking只会削弱你的精力&#xff0c;虚度你的光阴&#xff0c;每天迈出一小步&#xff0c;回头时发现已经走了很远。 &#x1f4d7;概念 在Go语言中&#xff0c;泛型&#xff08;Generics&#xff09;允许你编写可以处理…

Web前端开发--HTML语言

文章目录 前言1.介绍2.组成3.基本框架4.常见标签4.1双标签4.1.1.标题标签4.2.2段落标签4.1.3文本格式化标签4.1.4超链接标签4.1.5视频标签4.1.6 音频标签 4.2单标签4.2.1换行标签和水平线标签4.2.2 图像标签 5.表单控件结语 前言 生活中处处都有网站&#xff0c;无论你是学习爬…

数据结构-图的概念

不存在空图现象,顶点集不能为空,边集可以为空 研究链接一个顶点的边有多少条非常有意义 无向图的度边的二倍 有向图的入度出度,度边数 有向图一致 重点 子图必须联通,尽可能多的边和结点 对于一个生成树,他有n个节点就有n-1条边 修路问题将各个村庄相连,由于经费有限,只能选择…

TDengine 签约蘑菇物联,改造通用设备工业互联网平台

在当前工业互联网迅猛发展的背景下&#xff0c;企业面临着日益增长的数据处理需求和智能化转型的挑战。通用工业设备的高能耗问题愈发突出&#xff0c;尤其是由这些设备组成的公辅能源车间&#xff0c;亟需更高效的解决方案来提升设备运行效率&#xff0c;降低能源消耗。为此&a…

LSM-TREE和SSTable

一、什么是LSM-TREE LSM Tree 是一种高效的写优化数据结构&#xff0c;专门用于处理大量写入操作 在一些写多读少的场景&#xff0c;为了加快写磁盘的速度&#xff0c;提出使用日志文件追加顺序写&#xff0c;加快写的速度&#xff0c;减少随机读写。但是日志文件只能遍历查询…

vue3使用easy-player播放hls监控流

easy-player未发布在npm上&#xff0c;只能采用静态引入方式&#xff0c;老版本不支持v3 1. 在public文件夹下放入EasyPlayer-element.min.js 和 EasyPlayer.wasm 文件 2. 在根目录index.html引入 这样在vue文件中可以使用easy-player 标签 附件

【VScode】C/C++多文件夹下、多文件引用、分别编译——仅一个设置【适合新人入手】

【VScode】C/C多文件夹内的多文件引用编译 1、问题2、前提&#xff08;最简环境&#xff09;3、核心&#xff08;关键配置&#xff09;4、成功享用~ 1、问题 在使用 VScode 编写一个简单项目的时候&#xff0c;没有特别配置的情况下&#xff0c;若主文件(.c)引用了自定义的头文…

【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!

数据集介绍 【数据集】道路事故识别数据集 8939 张&#xff0c;目标检测&#xff0c;包含YOLO/VOC格式标注。数据集中包含2种分类&#xff1a;{0: accident, 1: non-accident}。数据集来自国内外图片网站和视频截图。检测范围道路事故检测、监控视角检测、无人机视角检测、等&…

Scala 的包及其导入

Scala使用包来创建用于模块化程序的命名空间。通过在Scala文件的顶部声明一个或多个包名称可以创建包&#xff0c;另一种声明包的方式是使用0&#xff0c;这种方式可以嵌套包&#xff0c;并且提供更好的范围与封装控制。对于包的导入&#xff0c;Scala与Java的区别之一便是&…

使用 HuggingFace 提供的 Elasticsearch 托管交叉编码器进行重新排名

作者&#xff1a;来自 Elastic Jeff Vestal 了解如何使用 Hugging Face 的模型在 Elasticsearch 中托管和执行语义重新排序。 在这篇简短的博文中&#xff0c;我将向你展示如何使用 Hugging Face 中的模型在搜索时在你自己的 Elasticsearch 集群中执行语义重新排序。我们将使用…

深究JS底层原理

一、JS中八种数据类型判断方法 在JavaScript中&#xff0c;数据类型分为两大类&#xff1a;基本&#xff08;原始&#xff09;数据类型和引用&#xff08;对象&#xff09;数据类型。 基本数据类型&#xff08;Primitive Data Types&#xff09; 基本数据类型是表示简单的数…

C++虚继承演示

在继承中如果出现&#xff1a; 这种情况&#xff0c;B和C都继承了A&#xff0c;D继承了B、C 在D中访问A的成员会出现&#xff1a; 这样的警告 是因为在继承时A出现两条分支&#xff1a;ABD、ACD 编译器不知道访问的A中的元素是经过B继承还是C继承 所以B、C在继承A时要用到…

【1】虚拟机安装

1.安装VMware WorkStation Pro VMware下载地址&#xff1a; 密钥&#xff1a;YF390-0HF8P-M81RQ-2DXQE-M2UT6 2.新建虚拟机 centos7下载地址&#xff1a;centos-7.9.2009-isos-x86_64安装包下载_开源镜像站-阿里云

【机器学习】均方误差根(RMSE:Root Mean Squared Error)

均方误差根&#xff08;Root Mean Squared Error&#xff0c;RMSE&#xff09;是机器学习和统计学中常用的误差度量指标&#xff0c;用于评估预测值与真实值之间的差异。它通常用于回归模型的评价&#xff0c;以衡量模型的预测精度。 RMSE的定义与公式 给定预测值 和实际值 …

python可视化进阶

引用&#xff1a; 首先需要安装 plotnine from plotnine import* import joypy数据可视化进阶操作 3.1 类别数据可视化 【例3-1】——绘制简单条形图 【代码框3-1】——绘制简单条形图 # 图3-1的绘制代码 import pandas as pd import matplotlib.pyplot as plt from cvxpy …

玩的花,云产品也能拼团了!!!

说起拼单大家都不陌生&#xff0c;电商一贯的营销手段&#xff0c;不过确实可以给消费者省下一笔钱。双11到了&#xff0c;腾讯云产品也玩起了拼团&#xff0c;这明显是对开发人员和各企业的福利。 对于有云产品需求的个人或企业&#xff0c;这次绝对是难得的一次薅羊毛机会。…