Java并发: CountDownLatch、CyclicBarrier和Semaphore

Java并发工具类:CountDownLatch、Semaphore、CyclicBarrier、Exchanger、Phaser 写在前面        在 Java 多线程环境下,JDK 提供了许多的工具类来供开发者使用,这些工具类都在java.util.concurrent 并发包下(俗称JUC),使得我们不需要过多的关心具体业务场景下,应该如何写出同时兼顾线程安全性与高效率的代码。之前文章介绍的:Java 线程池内容,全在这里了,也是 JUC 包下的... 阅读详情


这次说一下 JUC 中的同步器三个主要的成员:CountDownLatch、CyclicBarrier 和Semaphore(不知道有没有初学者觉得这三个的名字不太好记)。这三个是 JUC 中较为常用的同步器,通过它们可以方便地实现很多线程之间协作的功能。(下面的代码出自 JDK 文档)

CountDownLatch

直译过来就是倒计数(CountDown)门闩(Latch)。倒计数不用说,门闩的意思顾名思义就是阻止前进。在这里就是指 CountDownLatch.await() 方法在倒计数为0之前会阻塞当前线程。

作用

CountDownLatch 的作用和 Thread.join() 方法类似,可用于一组线程和另外一组线程的协作。例如,主线程在做一项工作之前需要一系列的准备工作,只有这些准备工作都完成,主线程才能继续它的工作。这些准备工作彼此独立,所以可以并发执行以提高速度。在这个场景下就可以使用CountDownLatch 协调线程之间的调度了。在直接创建线程的年代(Java 5.0 之前),我们可以使用 Thread.join()。在 JUC 出现后,因为线程池中的线程不能直接被引用,所以就必须使用CountDownLatch 了。

示例

下面的这个例子可以理解为 F1 赛车的维修过程,只有 startSignal (可以表示停车,可能名字不太贴合)命令下达之后,维修工才开始干活,只有等所有工人完成工作之后,赛车才能继续。

class Driver { // ...
    void main() throws InterruptedException {
        CountDownLatch startSignal = new CountDownLatch(1);
        CountDownLatch doneSignal = new CountDownLatch(N);

        for (int i = 0; i < N; ++i) // create and start threads
            new Thread(new Worker(startSignal, doneSignal)).start();

        doSomethingElse();            // don't let run yet
        startSignal.countDown();      // let all threads proceed
        doSomethingElse();
        doneSignal.await();           // wait for all to finish
    }
}

class Worker implements Runnable {
    private final CountDownLatch startSignal;
    private final CountDownLatch doneSignal;
    Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
        this.startSignal = startSignal;
        this.doneSignal = doneSignal;
    }
    public void run() {
        try {
            startSignal.await();
            doWork();
            doneSignal.countDown();
        } catch (InterruptedException ex) {} // return;
    }

    void doWork() { ... }
}

当 startSignal.await() 会阻塞线程,当 startSignal.countDown() 被调用之后,所有Worker 线程开始执行 doWork() 方法,所以 Worker。doWork() 是几乎同时开始执行的。当Worker.doWork() 执行完毕后,调用 doneSignal.countDown(),在所有 Worker 线程执行完毕之后,主线程继续执行。

CyclicBarrier

CyclicBarrier 翻译过来叫循环栅栏、循环障碍什么的(还是有点别扭的。所以还是别翻译了,只可意会不可言传啊)。它主要的方法就是一个:await()。await() 方法每被调用一次,计数便会减少1,并阻塞住当前线程。当计数减至0时,阻塞解除,所有在此CyclicBarrier 上面阻塞的线程开始运行。在这之后,如果再次调用 await() 方法,计数就又会变成 N-1,新一轮重新开始,这便是 Cyclic 的含义所在。

CyclicBarrier 的使用并不难,但需要注意它所相关的异常。除了常见的异常,CyclicBarrier.await() 方法会抛出一个独有的BrokenBarrierException。这个异常发生在当某个线程在等待本 CyclicBarrier 时被中断或超时或被重置时,其它同样在这个CyclicBarrier 上等待的线程便会受到 BrokenBarrierException。意思就是说,同志们,别等了,有个小伙伴已经挂了,咱们如果继续等有可能会一直等下去,所有各回各家吧。

CyclicBarrier.await() 方法带有返回值,用来表示当前线程是第几个到达这个 Barrier 的线程。

和 CountDownLatch 一样,CyclicBarrier 同样可以可以在构造函数中设定总计数值。与CountDownLatch 不同的是,CyclicBarrier 的构造函数还可以接受一个 Runnable,会在CyclicBarrier 被释放时执行。

NOTE: CyclicBarrier 的功能也可以由 CountDownLatch 来实现

示例

CyclicBarrier 的应用(当然,这个例子换成 CountDownLatch 也是可以实现的,很简单,就不说怎么写了)

class Solver {
    final int N;
    final float[][] data;
    final CyclicBarrier barrier;

    class Worker implements Runnable {
        int myRow;
        Worker(int row) { myRow = row; }
        public void run() {
            while (!done()) {
                processRow(myRow);

                try {
                    barrier.await();
                } catch (InterruptedException ex) {
                    return;
                } catch (BrokenBarrierException ex) {
                    return;
                }
            }
        }
    }

    public Solver(float[][] matrix) {
        data = matrix;
        N = matrix.length;
        barrier = new CyclicBarrier(N, new Runnable() {
                public void run() {
                    mergeRows(...);
                }
            });
        for (int i = 0; i < N; ++i)
            new Thread(new Worker(i)).start();

        waitUntilDone();
    }
}

CyclicBarrier 和 CountDownLatch 在用法上的不同

CountDownLatch 适用于一组线程和另一个主线程之间的工作协作。一个主线程等待一组工作线程的任务完毕才继续它的执行是使用CountDownLatch 的主要场景;CyclicBarrier用于一组或几组线程,比如一组线程需要在一个时间点上达成一致,例如同时开始一个工作。另外,CyclicBarrier 的循环特性和构造函数所接受的Runnable 参数也是CountDownLatch 所不具备的。

Semaphore

Semaphore 直译是信号量,可能称它是许可量更容易理解。当然,因为在计算机科学中这个名字由来已久,所以不能乱改。它的功能比较好理解,就是通过构造函数设定一个数量的许可,然后通过acquire 方法获得许可,release 方法释放许可。它还有 tryAcquire 和acquireUninterruptibly 方法,可以根据自己的需要选择

示例:Semaphore 控制资源访问

class Pool {
    private static final int MAX_AVAILABLE = 100;
    private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);

    public Object getItem() throws InterruptedException {
        available.acquire();
        return getNextAvailableItem();
    }

    public void putItem(Object x) {
        if (markAsUnused(x))
            available.release();
    }

    // Not a particularly efficient data structure; just for demo

    protected Object[] items = ... whatever kinds of items being managed
    protected boolean[] used = new boolean[MAX_AVAILABLE];

    protected synchronized Object getNextAvailableItem() {
        for (int i = 0; i < MAX_AVAILABLE; ++i) {
            if (!used[i]) {
                used[i] = true;
                return items[i];
            }
        }
        return null; // not reached
    }

    protected synchronized boolean markAsUnused(Object item) {
        for (int i = 0; i < MAX_AVAILABLE; ++i) {
            if (item == items[i]) {
                if (used[i]) {
                    used[i] = false;
                    return true;
                } else
                    return false;
            }
        }
        return false;
    }
}

上面这个示例中 Semaphore 的用法没什么可多讲的。需要留言的是这里面有两个同步方法,不过对吞吐应该没什么影响,因为主要是对一个 boolean 数组做一下 O(n) 的操作,而且每个循环里面的操作很简单,所以速度很快。不过不知道 JUC 里面线程池的控制是怎么做的,本人不才,还没看过那块源代码,得空看看,有知道的也可以说说。

最后一句话总结

CountDownLatch 是能使一组线程等另一组线程都跑完了再继续跑;CyclicBarrier 能够使一组线程在一个时间点上达到同步,可以是一起开始执行全部任务或者一部分任务。同时,它是可以循环使用的;Semaphore 是只允许一定数量的线程同时执行一段任务。


simulink构建一个基于 BP(反向传播)神经网络 的自适应 PID 控制系统 本文介绍了基于BP神经网络的自适应PID控制系统设计方法。系统通过神经网络实时调整PID参数,实现智能控制。主要内容包括:1)系统架构设计,采用误差反馈和在线学习机制;2)详细建模步骤,从被控对象定义到神经网络结构设计;3)S-Function实现核心算法,包含前向传播、PID计算和反向传播;4)仿真结果分析,显示神经网络PID在响应速度、超调控制和鲁棒性方面的优势;5)进阶建议和常见问题解决方案。该方法突破了传统PID的局限性,实现了具有自我学习能力的智能控制。 阅读详情

相关推荐

别再死记硬背了!用Multisim仿真5分钟搞懂运放电压跟随器到底要不要加反馈电阻

本文通过Multisim仿真实验,深入解析运放电压跟随器中反馈电阻的必要性。实验对比不同阻值对电路性能的影响,揭示反馈电阻在提供偏置电流通路、提升高频稳定性和ESD保护中的关键作用,并给出工程实践中的优化建议,帮助工程师快速掌握运放电路设计要点。

weixin_42641998的博客 371

循环栅栏 CycleBarrier 理解到深入

介绍 CycleBarrier,从一个例子开始理解,然后深入源码分析对应的实现

Wayfreem的博客 2660

常规波束形成——时域波束形成、频域波束形成

本文介绍了波束成形,包括时域波束成形和频域波束成形,并解释了在实现过程可能存在疑惑的相位补偿。

Candy_Editor的博客 3657

线程中run()方法和start()方法区别,为什么在调用start()时,会执行run()方法

1.线程中run()方法和start()方法区别 run方法是线程中的一个普通方法体,可以重复调用。是线程里的一个函数,不是多线程,直接调用run方法,相当于调用一个普通函数,执行路径还是一条, 根本没有多线程的特征。 而start方法是Thread中的线程启动方法,只能调用一次,且调用之后,线程就是就绪状态,时间片获取之后即可执行run方法中的内容。 start方法来启动一个线程,真正实现了多线程运算,调用start方法无需等待run方法运行完成,可以直接继续执行其他代码;run方法执行完毕,线程终止,然

JIESHAO优快云的博客 1193

手把手教你用Qwen-7B打造医疗大模型:从数据准备到RLHF全流程实战

本文是一篇基于Qwen-7B-Chat模型构建医疗领域大模型的实战全流程指南。文章详细拆解了从数据准备、环境搭建,到增量预训练、监督微调(SFT)以及偏好对齐(DPO)的核心技术步骤,并分享了部署与持续优化的实践经验。通过LoRA等高效微调技术,帮助开发者掌握将通用大模型改造为专业领域专家的完整方法论。

weixin_29191761的博客 129

泰森多面体Voronoi 3D-V5.0 功能介绍

Abaqus Voronoi3D

qq_34840441的博客 3364

CountDownLatch原理解析

CountDownLatch是多线程控制的一种同步工具类,它被称为门阀、 计数器或者闭锁。这个工具经常用来用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用)。 它允许一个或多个线程一直等待,直到其他线程执行完后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有框架服务之后执行。

m0_38033199的博客 822

OpenCV实例(八)车牌字符识别技术(三)汉字识别

相较于数字和英文字符的识别,汽车牌照中的汉字字符识别的难度更大,主要原因有以下4个方面:(1)字符笔画因切分误差导致非笔画或笔画流失。(2)汽车牌照被污染导致字符上出现污垢。(3)采集所得车辆图像分辨率低导致多笔画的汉字较难分辨。(4)车辆图像采集时所受光照影响的差异导致笔画较淡。综合汉字识别时的这些难点来看,很难被直接提取的是字符的局部特征。笔画作为最重要的特征而仅存在于汉字中,这由先验知识可知。一旦捺、横、竖、撇这些笔画特征被提取到,对于汉字字符识别的工作就完成了许多。

小幽余生不加糖 1650

深入理解CountDownLatch原理

深入理解CountDownLatch原理 一、简介 CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程执行完后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有框架服务之后执行。CountDownLatch是在java1.5被引入的,跟它一起被引入的并发工具类还...

Touch 2342

手把手教你使用ConvNeXt训练自己数据集和推理,ConvNeXt模型训练(CVPR 2022),一个能挑战 Vision Transformer 的卷积神经网络,含完整代码和数据集

手把手教你使用ConvNeXt训练自己数据集和推理,ConvNeXt模型训练(CVPR 2022),一个能挑战 Vision Transformer 的卷积神经网络,含完整代码和数据集

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 1449

基于 Simulink 的 PV 光伏阵列功率发电系统仿真 Matlab

其中直流侧电压需要与光伏电池组件匹配,交流侧电压则需要与配电系统匹配,开关频率一般在几千赫兹左右,需要保证在一定范围内。根据实际需求,我们还可以通过增加负载,以及调节光照强度等方式,模拟不同的情况下系统的响应和性能表现。经过设置参数和各部分之间的传递和控制后,我们可以开始进行模型仿真。在仿真前,我们需要确定仿真时间和步长,并对整体模型进行编译。在建立完毕整体模型框架后,我们需要为每个组件设置参数,并进行传递和控制。首先,我们需要建立一个整体的模型框架,包括各个组件之间的关系和控制器的作用。

学习使你进步。 1128

【多线程】CountDownLatch实现原理

前言 CountDownLatch是多线程中一个比较重要的概念,它可以使得一个或多个线程等待其他线程执行完毕之后再执行。它内部有一个计数器和一个阻塞队列,每当一个线程调用countDown()方法后,计数器的值减少1。当计数器的值不为0时,调用await()方法的线程将会被加入到阻塞队列,一直阻塞到计数器的值为0。 常用方法 public class CountDownLatch { //构造一个值为count的计数器 public CountDownLatch(int count

阳阳的博客 3487

一条 POST 创建整棵业务对象树,SAP Gateway Deep Create 的运行机制与 ABAP 实现

SAPUI5 的 OData V2 Model 支持 Deep Create,可以为一个新建的 transient parent context 创建 Navigation Property 下的 subentity,并把这些子实体的数据合并进 Root Entity 对应的 OData 请求 Payload。销售组织是否合法,客户是否允许下单,物料是否存在,销售区域是否匹配,计量单位是否正确,项目类别如何确定,定价是否成功,合作伙伴如何派生,交货工厂如何确定,这些都可能在一次创建过程中被触发。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 146

Java并发编程:CountDownLatch、CyclicBarrier和Semaphore

一.CountDownLatch用法:  CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。   CountDownLatch类只提供了一个构造器: 1 publicCountDo...

雪锋的笔记 336

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

JAVA并发编程: CountDownLatch,CyclicBarrier 和 Semaphore

CyclicBarrier CountDownLatch Semaphore Reference / 参考: https://www.fangzhipeng.com/javainterview/2019/03/21/latch-barrier-semaphore.html

村里的原振侠的博客 364

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Java中的并发工具类:CountDownLatch、CyclicBarrier、Semaphore详解

适用于一个或多个线程等待其他线程完成操作后再继续执行的场景。:适用于多个线程相互等待,直到所有线程都到达某个屏障点后再继续执行的场景,且可以重复使用。Semaphore:适用于控制同时访问某个资源的线程数量,常用于资源池的管理。根据具体的需求选择合适的并发工具类,可以有效地协调多线程之间的同步,提高程序的并发性能。

吴晓斌的博客 958

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Java 并发工具类:CountDownLatch、CyclicBarrier、Semaphore 详解

是一个同步辅助类,它允许一个或多个线程等待其他线程完成操作。其内部维护了一个计数器,该计数器的初始值由构造函数指定,每当一个线程完成任务后,会调用方法将计数器减 1,当计数器的值变为 0 时,等待在await()方法上的线程将被唤醒继续执行。是一个同步辅助类,它允许一组线程相互等待,直到所有线程都到达某个公共屏障点(barrier point)。与不同的是,可以被重复使用,当所有线程都到达屏障点后,计数器会被重置,可以继续进行下一轮的等待。Semaphore。

dsq_MaDing的博客 782

【Java并发】CountDownLatch+CyclicBarrier+Semaphore:样例入门篇

1 CountDownLatch 倒计时门闩:[ˈkaʊntdaʊn] [lætʃ],顾名思义,门闩有多个,当门闩全部开启时,门闩数减为0,才能把门打开,在门前等待的人才能出去。 来个例子:在线程池中,并发执行10个任务,主线程观察任务执行情况,并等待任务全部执行结束,输出执行结果。 // 创建线程池,核心池-0,最大-10,timeout-0,队列-实时队列 // 当有任务来的时候,会立...

qqchaozai的专栏 332

Java并发编程:CountDownLatch、CyclicBarrier与Semaphore详解

并发编程中的线程协调是提升系统性能的关键技术。通过同步工具控制线程执行顺序,可以解决资源竞争、任务依赖等典型问题。Java并发包提供的CountDownLatch适用于一次性事件等待场景,CyclicBarrier实现线程间的循环同步,而Semaphore则用于控制资源访问并发量。这些工具在电商库存校验、分布式计算等高频并发场景中具有重要应用价值。合理使用这些同步器能显著提升系统吞吐量,其中CountDownLatch的计数器机制和Semaphore的许可证模型尤其值得开发者掌握。

weixin_31292729的博客 281
上一篇: MySQL索引背后的数据结构及算法(吐血推荐)
下一篇: CLOSE_WAIT状态的原因与解决方法
大树叶
博客等级 码龄12年 1171粉丝 664原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值