多线程的闭锁和栅栏

article/2025/10/4 8:40:59

多线程的闭锁和栅栏

JAVA并发包中有三个类用于同步一批线程的行为,分别是闭锁(Latch),信号灯(Semaphore)和栅栏(CyclicBarrier)。这里我们主要来介绍一下:

闭锁(Latch)

闭锁即是一种同步方法,可以延迟线程的进度直到线程到达某个终点状态

通俗的讲就是,一个闭锁相当于一扇大门,在大门打开之前所有线程都被阻断,一旦大门打开所有线程都将通过,但是一旦大门打开,所有线程都通过了,那么这个闭锁的状态就失效了,门的状态也就不能变了,只能是打开状态。也就是说闭锁的状态是一次性的,它确保在闭锁打开之前所有特定的活动都需要在闭锁打开之后才能完成。

其中一个具体的例子就是我们的计数器闭锁(CountDownLatch),它是JDK5+中闭锁的一个实现,允许一个或者多个线程等待某一个事件的发生。

CountDownLatch 有个正数的计数器,countDown(): 对计数器做减法操作;await(): 等待计数器 = 0。

所有await的线程都会阻塞,直到计数器为0或者等待线程中断或者超时。

我们使用代码来举一个例子:

//MyRunnable类
public class MyRunnable implements Runnable{private final CountDownLatch await;private final int num;public MyRunnable(CountDownLatch await, int num) {this.await = await;this.num = num;}@Overridepublic void run() {System.out.println("线程" + num + "执行完毕...");await.countDown();   //当前事件执行完毕,计数减1}
}//测试类
public class TestCountDown {public static void main(String[] args) throws InterruptedException {CountDownLatch await = new CountDownLatch(5);for (int i = 1; i < 6; i++) {new Thread(new MyRunnable(await,i)).start();}System.out.println("等待线程运行结束...");await.await();System.out.println("五个线程已经运行结束...");}
}

输出结果:

线程1执行完毕...
等待线程运行结束...
线程4执行完毕...
线程2执行完毕...
线程3执行完毕...
线程5执行完毕...
五个线程已经运行结束...

说明主线程await以后,必须等待这五个线程运行结束才会执行

在这里插入图片描述

我们再来举一个例子:

此时三个工人在为老板干活,这个老板有一个习惯,就是当三个工人把一天的活都干完了的时候,他就来检查所有工人所干的活。记住这个条件:三个工人先全部干完活,老板才检查。

Worker工人类:

public class Worker implements Runnable{private CountDownLatch downLatch;private String name;public Worker(CountDownLatch downLatch, String name) {this.downLatch = downLatch;this.name = name;}@Overridepublic void run() {this.work();try {Thread.sleep(new Random().nextInt(1000));System.out.println(this.name + "活干完了...");this.downLatch.countDown();} catch (InterruptedException e) {e.printStackTrace();}}private void work() {System.out.println(this.name + "正在干活...");}
}

Boss包工头类:

public class Boss implements Runnable{private CountDownLatch downLatch;public Boss(CountDownLatch downLatch) {this.downLatch = downLatch;}@Overridepublic void run() {System.out.println("包工头等待工人干完活...");try {this.downLatch.await();System.out.println("工人们已经干完活了,现在进行检查...");} catch (InterruptedException e) {e.printStackTrace();}}
}

TestLauch测试类:

public class TestLatch {public static void main(String[] args) {CountDownLatch latch = new CountDownLatch(5);ExecutorService executorService = Executors.newCachedThreadPool();Worker worker1 = new Worker(latch, "张三");Worker worker2 = new Worker(latch, "李四");Worker worker3 = new Worker(latch, "王五");Worker worker4 = new Worker(latch, "赵六");Worker worker5 = new Worker(latch, "冯七");Boss boss = new Boss(latch);executorService.execute(worker1);executorService.execute(worker2);executorService.execute(worker3);executorService.execute(worker4);executorService.execute(worker5);executorService.execute(boss);executorService.shutdown();}
}

输出结果:

张三正在干活...
赵六正在干活...
王五正在干活...
李四正在干活...
包工头等待工人干完活...
冯七正在干活...
李四活干完了...
张三活干完了...
王五活干完了...
赵六活干完了...
冯七活干完了...
工人们已经干完活了,现在进行检查...

栅栏(CyclicBarrier)

栅栏类似于闭锁,它能阻塞一组线程直到某个事件发生。 栅栏与闭锁的关键区别在于,所有的线程必须同时到达栅栏位置,才能继续执行。闭锁用于等待事件,而栅栏用于等待其他线程。

场景: 接着上面的例子,还是这三个工人,不过这一次,这三个工人自由了,老板不用检查他们任务了,他们三个合作建桥,有三个桩,每人打一个,同时打完之后才能一起搭桥(搭桥需要三人一起合作)。也就是说三个人都打完桩之后才能继续工作。

Worker类:

public class Worker implements Runnable{private CyclicBarrier cyclicBarrier;private String name;public Worker(CyclicBarrier cyclicBarrier,String name) {this.cyclicBarrier = cyclicBarrier;this.name = name;}@Overridepublic void run() {try {this.work();Thread.sleep(new Random().nextInt(1000));this.waitOther();cyclicBarrier.await();this.continueWork();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}}private void work() {System.out.println(this.name + "正在干活...");}private void waitOther() {System.out.println(this.name + "当前这部分工作干完了,等等他们吧...");}private void continueWork() {System.out.println("大家都干完这部分活了," + this.name + "又得忙活了...");}}

TestCycleBarrier测试类:

public class TestCycleBarrier {public static void main(String[] args) {CyclicBarrier cyclicBarrier = new CyclicBarrier(5);ExecutorService es = Executors.newCachedThreadPool();es.execute(new Worker(cyclicBarrier,"张三"));es.execute(new Worker(cyclicBarrier,"李四"));es.execute(new Worker(cyclicBarrier,"王五"));es.execute(new Worker(cyclicBarrier,"赵六"));es.execute(new Worker(cyclicBarrier,"冯七"));es.shutdown();}
}

输出结果:

张三正在干活...
冯七正在干活...
赵六正在干活...
李四正在干活...
王五正在干活...
李四当前这部分工作干完了,等等他们吧...
赵六当前这部分工作干完了,等等他们吧...
张三当前这部分工作干完了,等等他们吧...
王五当前这部分工作干完了,等等他们吧...
冯七当前这部分工作干完了,等等他们吧...
大家都干完这部分活了,冯七又得忙活了...
大家都干完这部分活了,李四又得忙活了...
大家都干完这部分活了,王五又得忙活了...
大家都干完这部分活了,张三又得忙活了...
大家都干完这部分活了,赵六又得忙活了..

在这里插入图片描述

闭锁和栅栏的区别:

  • 闭锁用于所有线程等待一个外部事件的发生;栅栏则是所有线程相互等待,直到所有线程都到达某一点时才打开栅栏,然后线程可以继续执行。

http://chatgpt.dhexx.cn/article/oFjc97CO.shtml

相关文章

分布式锁(Distributed Lock)理论介绍

在多线程环境中&#xff0c;线程之间通常使用互斥锁实现共享资源的独占访问。在多进程环境&#xff0c;特别是分布式环境&#xff0c;常使用分布式锁来实现共享资源的独占访问。简单来说&#xff0c;分布式锁就是指在分布式环境下&#xff0c;通过加解锁实现多节点对共享资源的…

迟滞电路 平稳欠压和过压闭锁

下述的等式假设比较器输入端的输入偏置电流为0&#xff0c;而示例只考虑了电阻比&#xff0c;而未考虑绝对值。比较器输入同时具有输入失调电压(VOS)、参考误差&#xff08;也可以与VOS合并&#xff09;&#xff0c;以及输入偏置电流或漏电流(ILK)。如果分压器偏置电流&#xf…

偏向锁

流程讲解 当JVM启用了偏向锁模式&#xff08;JDK6以上默认开启&#xff09;&#xff0c;新创建对象的Mark Word中的Thread Id为0&#xff0c;说明此时处于可偏向但未偏向任何线程&#xff0c;也叫做匿名偏向状态(anonymously biased)。 偏向锁逻辑 1.线程A第一次访问同步块时&…

什么是间隙锁?

什么是间隙锁? 间隙锁是一个在索引记录之间的间隙上的锁。 间隙锁的作用 保证某个间隙内的数据在锁定情况下不会发生任何变化。比如mysql默认隔离级别下的可重复读(RR)。 当使用唯一索引来搜索唯一行的语句时,不需要间隙锁定。如下面语句的id列有唯一索引,此时只会对id值…

锁消除、锁粗化、偏向锁、适应性锁

文章目录 锁消除锁粗化偏向锁适应性锁 锁消除 锁消除是JIT编译器对内部锁实现的一种优化。JIT可以借助逃逸分析来判断同步块的锁对象是否只是被一个线程访问&#xff0c;如果是的话&#xff0c;则在编译期间不生成内部锁的申请与释放对应的机器码&#xff0c;即消除了锁的使用…

多线程并发之CountDownLatch(闭锁)使用详解

专题相关文章&#xff1a; 从内存可见性看Volatile、原子变量和CAS算法 多线程并发之CountDownLatch(闭锁)使用详解 多线程并发之显示锁Lock与其通信方式Condition源码解读 多线程并发之读写锁(ReentranReadWriteLock&ReadWriteLock)使用详解 多线程并发之线程池Executor与…

【ABAQUS】什么是剪切闭锁?剪切闭锁会导致什么?

“完全积分”是指当单元具有规则形状时&#xff0c;对单元刚度矩阵中的多项式项进行精确积分所需的高斯点数。对于六面体和四边形元素&#xff0c;“规则形状”意味着边缘是直的&#xff0c;并以直角相交&#xff0c;任何边缘节点都位于边缘的中点。 完全积分的线性元素在每个…

电力“五防”闭锁系统

&#xff08;转载&#xff09; 电力“五防”闭锁系统 随着电子技术在各个行业领域的飞速发展&#xff0c;电力的“五防”也将发生革命性的转变。现代电力系统规模不断扩大&#xff0c;从而促使电压的等级也得到了进一步提高。为了使电力系统的安全稳定运行能够得以充分保障&am…

【LB-1A 100V电压回路断相闭锁继电器】

系列型号 LB-1A电压回路断相闭锁继电器 LB-1A闭锁继电器 1 用途 LB-1A型电压回路断相闭锁继电器&#xff08;以下简称继电器&#xff09;是在交流电压回路断线而可能引起继电保护误动作时&#xff0c;对继电保护进行闭锁。该继电器用于中性点非直接接地系统中。 2 结构与工作原…

间隙锁

一.几个基本概念 行锁&#xff1a;给某一行加的锁间隙锁&#xff1a;就是两个值之间的间隙。为了解决幻读问题&#xff0c;InnoDB 只好引入新的锁&#xff0c;也就是 间隙锁 (Gap Lock)。间隙锁Gap,左右都是开区间&#xff0c;间隙锁行锁合称next-key lock,每个 next-key lock…

闭锁,信号量,栅栏

1. 闭锁&#xff08;countDownLatch&#xff09; 1.1. 作用&#xff1a; 相当于一扇门&#xff0c;在闭锁到达结束状态之前&#xff0c;这扇门是关着的&#xff0c;所以的线程都不允许通过&#xff0c;当闭锁到达结束状态&#xff0c;这扇门打开并允许所有的线程通过。在…

visio 2010激活教程

一、下载office2010toolkit.zip 若下载链接失效&#xff0c;手动搜索office2010toolkit http://ys-c.ys168.com/605279628/o4W138W45JIPI5SiuWf5/office2010toolkit.zip二、激活 激活过程中需要关闭office套件

Microsoft Visio Professional 2013 安装步骤

1.打开解压后的文件夹&#xff0c;点击setup.exe安装 2.勾选我接受此协议的条款&#xff0c;继续 3.点击立即安装 4.安装完成&#xff0c;关闭。 5.打开第一步解压的文件夹中破解文件夹&#xff0c;鼠标右键以管理员身份运行 6.点击激活office2013VL 7.激活完成 Microsoft Visi…

激活Visio2013

最近需要用Visio&#xff0c;由于密钥过期了&#xff0c;也不知道怎么重新输密钥&#xff0c;于是网上搜索&#xff0c;终于找到了一个方法。 KMSpico工具&#xff0c;安装完后直接打开点击左边红色按钮就可以了。如图&#xff1a; 最后附上工具链接https://pan.baidu.com/s/1…

机器学习十大算法之-CART分类决策树、回归树和模型树

转载&#xff08;http://blog.163.com/zhoulili1987619126/blog/static/35308201201542731455261/&#xff09; Classification And Regression Tree(CART)是决策树的一种&#xff0c;并且是非常重要的决策树&#xff0c;属于Top Ten Machine Learning Algorithm。顾名思义&…

决策树入门以及树模型的参数选择

决策树及树模型的参数选择 决策树的基本概念 在数据结构中树是一个重要的数据结构&#xff0c;这里树被我们根据分支起到一个决策的作用。什么是决策&#xff1f;通俗的说就是判断或者决定&#xff0c;我们引用周志华的西瓜书中的例子&#xff1a;这是一个好瓜吗&#xff1f;当…

gbdt、xgb、lgb决策树模型

目录 1.决策树1.1 CART分类树1.2 CART回归树 2.gbdt3.xgboost4.lightgbm5.模型对比6.参考文献 本文主要对决策树、gbdt、xgboost、lightgbm、catboost进行简述和整理&#xff0c;包括模型原理、优劣性等内容 1.决策树 决策树是一种通过对历史数据进行测算&#xff0c;对新数据…

树模型与线性模型的融合模型(Python实现)

目录 一、树模型与线性模型的融合模型 二、Python sklearn实现GBDTLR融合模型 一、树模型与线性模型的融合模型 树模型GBDT原理&#xff1a;https://blog.csdn.net/woniu201411/article/details/83114226 线性模型LR原理&#xff1a;https://blog.csdn.net/woniu201411/art…

机器学习理论与实战(九)回归树和模型树

前一节的回归是一种全局回归模型,它设定了一个模型,不管是线性还是非线性的模型,然后拟合数据得到参数,现实中会有些数据很复杂,肉眼几乎看不出符合那种模型,因此构建全局的模型就有点不合适。这节介绍的树回归就是为了解决这类问题,它通过构建决策节点把数据数据切分成…

决策树模型

本文代码及数据集来自《Python大数据分析与机器学习商业案例实战》 决策树模型的建树依据主要用到的是基尼系数的概念。基尼系数&#xff08;gini&#xff09;用于计算一个系统中的失序现象&#xff0c;即系统的混乱程度。基尼系数越高&#xff0c;系统的混乱程度就越高&#x…