并发编程CountDownLatch浅析

news2025/5/12 6:15:30

目录

  • 一、CountDownLatch简介
  • 二、源码
  • 三、使用
    • 3.1 demo1
    • 3.2 demo2
  • 四、应用场景
  • 五、参考链接


一、CountDownLatch简介

CountDownLatch(倒计时锁存器)是Java并发包中的一个工具类,用于实现多个线程之间的同步。它通过一个计数器来实现线程之间的等待和唤醒操作,允许一个或多个线程等待其他线程完成操作后再继续执行。

CountDownLatch的主要特点包括:

初始值设定:CountDownLatch被创建时需要指定一个初始计数值,表示需要等待的线程数量。
计数操作:通过countDown()方法对计数器进行减1操作,表示一个线程已经完成了任务。
等待操作:通过await()方法使当前线程等待,直到计数器值减至0。
唤醒操作:当计数器值减至0时,所有等待的线程将被唤醒继续执行。

CountDownLatch通常用于一组线程等待另一组线程完成任务后再继续执行,或者实现多个线程协同工作的场景。它可以帮助解决线程之间的依赖关系和协同问题,提高程序的并发性能和效率。


二、源码

public class CountDownLatch {

    private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;

        Sync(int count) {
            setState(count);
        }

        int getCount() {
            return getState();
        }

        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }

        protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c - 1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
    }

    private final Sync sync;

    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }


    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }


    public boolean await(long timeout, TimeUnit unit)
        throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }


    public void countDown() {
        sync.releaseShared(1);
    }


    public long getCount() {
        return sync.getCount();
    }


    public String toString() {
        return super.toString() + "[Count = " + sync.getCount() + "]";
    }
}

逐一解读各个方法

内部Sync类:

  • Sync类的构造函数:接受一个初始计数值count,并将其设置为当前状态。
  • getCount()方法:返回当前计数值。
  • tryAcquireShared(int acquires)方法:
    当尝试获取共享锁时调用。
    如果当前状态为0,表示可以获取锁,返回1;否则返回-1。
  • tryReleaseShared(int releases)方法:
    当释放共享锁时调用。
    通过循环不断尝试将状态值减1,直到减至0,然后返回false;循环过程中尝试使用CAS(Compare and Set)操作来将当前状态值更新为下一个状态值,并在更新成功后判断下一个状态值是否为0。简而言之,当前状态值为0返回false;CAS设置成功,下一个状态值为0返回true,否则返回false。


    CountDownLatch类:
  • 构造函数CountDownLatch(int count):创建一个CountDownLatch对象,接受一个初始计数值,如果初始计数值小于0,则抛出IllegalArgumentException异常。
  • await()方法:阻塞等待直到计数值为0,如果被中断则抛出InterruptedException异常。
  • await(long timeout, TimeUnit unit)方法:在指定的时间范围内等待,如果在超时之前计数值变为0则返回true,否则返回false。
  • countDown()方法:将计数值减1。
  • getCount()方法:返回当前计数值。
  • toString()方法:返回当前对象的字符串表示,包括计数值信息。

三、使用

3.1 demo1

  public static void test1() throws InterruptedException {

        CountDownLatch countDownLatch = new CountDownLatch(1);
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                try {
                    //所有请求都阻塞在这,等待
                    countDownLatch.await();
                    // 调用测试接口
                    System.out.println(Thread.currentThread().getName() + "开始执行……");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        System.out.println(Thread.currentThread().getName() + "主线程开始睡眠……");
        // 让请求都准备好
        Thread.sleep(2000);
        System.out.println(Thread.currentThread().getName() + "主线程睡眠完成……");
        // 让所有请求统一请求
        countDownLatch.countDown();
    }

通过CountDownLatch.await(),让多个参与者线程启动后阻塞等待,然后在主线程 调用CountDownLatch.countdown() 将计数减为0,让所有线程一起往下执行;以此实现了多个线程在同一时刻并发执行,来模拟并发请求的目的。
输出:
在这里插入图片描述

3.2 demo2

    public static void test1() {
        final CountDownLatch latch = new CountDownLatch(3);

        Runnable task = () -> {
            System.out.println("Task is running..."+ Thread.currentThread().getName());
            latch.countDown();
            System.out.println("Task is completed."+ Thread.currentThread().getName());
        };

        // 启动3个线程执行任务
        for (int i = 0; i < 3; i++) {
            new Thread(task).start();
        }

        try {
            latch.await(); // 等待所有任务完成
            System.out.println("All tasks are completed. Proceed with main task.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

这一次主线程wait阻塞,等到子线程() latch.countDown()运行完才继续执行主线程。
输出:
在这里插入图片描述

通过上面两个例子可以看到我们主要使用了await阻塞方法和countDown()减少计数值来控制多线程的运行。

四、应用场景

场景1 让多个线程等待:模拟并发,让并发线程一起执行,见demo1
场景2 让单个线程等待:多个线程(任务)完成后,进行汇总合并,见demo2

鄙人尝试单独使用CountDownLatch控制多个子线程的并发顺序,效果并不好,会添加很多变量,消耗额外资源,不建议在该场景下使用。

五、参考链接

Java高并发编程基础三大利器之CountDownLatch
CountDownLatch的两种常用场景

按照惯例,附美图一张
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

51单片机系列-单片机定时器

&#x1f308;个人主页&#xff1a;会编辑的果子君 &#x1f4ab;个人格言:“成为自己未来的主人~” 软件延时的缺点 延时过程中&#xff0c;CPU时间被占用&#xff0c;无法进行其他任务&#xff0c;导致系统效率降低&#xff0c;延时时间越长&#xff0c;该缺点就越明显&…

esp8266调试记录

连接笔记本电脑 使用笔记本电脑的USB接口为NodeMCU开发板供电&#xff0c;你需要确保电压和电流在安全范围内。虽然NodeMCU的输入输出电压限制为3.3V&#xff0c;但是大多数开发板都内置了电压调节器&#xff0c;可以从5V的USB电源降压到3.3V。因此&#xff0c;通常情况下&…

通用的springboot web jar包执行脚本,释放端口并执行jar包

1、通用的springboot web jar包执行脚本&#xff0c;释放端口并执行jar包&#xff1a; #!/bin/bash set -eDATE$(date %Y%m%d%H%M) # 基础路径 BASE_PATH/data/yitu-projects/yitu-xzhq/sftp # 服务名称。同时约定部署服务的 jar 包名字也为它。 SERVER_NAMEyitu-server # 环境…

【图论】拓补排序 - 邻接表

文章目录 题目&#xff1a;310. 最小高度树题目描述代码与注释 题目&#xff1a;310. 最小高度树 题目描述 代码与注释 func findMinHeightTrees(n int, edges [][]int) (ans []int) {if n 1 {return []int{0}}g : make([][]int, n)degree : make([]int, n) // 记录每个节点…

Android Studio字体大小调节

外观页面字体调节 settings->Appearance->User cunstom font 代码字体调节 Settings->Editor->Font此时logcat窗口、Build窗口和Ternimal窗口字体大小也会同步调节&#xff08;2023.2.1版本上验证&#xff09;

FFmpeg查看所有支持的编码/解码器/封装/解封装/媒体格式/滤镜

查看所有支持的编码器与解码器 ffmpeg -codecs 只查看所有编码器: ffmpeg -encoders 只查看所有解码器: ffmpeg -decoders 只查看H264编码器: ffmpeg -h encoderh264 只查看H264解码器: ffmpeg -h decoderh264 查看所有支持的封装: ffmpeg -muxers 查看所有支持的解封装…

【算法】数论(求质数)——蓝桥杯笔记、2.质数、7.质数、质数数目、纯质数、函数判断顺序的优化

文章目录 蓝桥杯2.质数7.质数质数数目纯质数 蓝桥杯 2.质数 求质数的几种方法&#xff1a; #include<iostream> #include<algorithm> using namespace std;bool is_primer1(int n) {if (n < 2) return n;//for (int i 2; i < n; i)for (int i 2; i < …

简历信息泄露?如何用图数据库技术解决简历泄露事件的反欺诈挑战

“金三银四”&#xff0c;又到了春招黄金期&#xff0c;但个人简历泄露的数据安全问题诸见报端&#xff0c;甚至在此前的3.15晚会报道中就揭露过招聘平台上的简历信息被泄露&#xff0c;不法分子通过各种渠道获取到简历&#xff0c;并用于欺诈活动&#xff0c;形成了一套庞大的…

ZK vs FHE

1. 引言 近期ZAMA获得7300万美金的投资&#xff0c;使得FHE获得更多关注。FHE仍处于萌芽阶段&#xff0c;是未来隐私游戏规则的改变者。FHE需与ZK和MPC一起结合&#xff0c;以发挥最大效用。如&#xff1a; Threshold FHE&#xff1a;将FHE与MPC结合&#xff0c;实现信任最小…

【Sql Server】通过Sql语句批量处理数据,使用变量且遍历数据进行逻辑处理

欢迎来到《小5讲堂》&#xff0c;大家好&#xff0c;我是全栈小5。 这是《Sql Server》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对…

c语言案例03-流程控制-if语句

c语言打卡-流程控制-if语句 一.在 C/C&#xff0c;if 函数或关键字具有判断功能&#xff0c;而判断这一操作必须基于给定条件&#xff0c;同样的&#xff0c;程序中使用 if 函数同样需要将判断条件作为参数传入&#xff0c;描述判断条件的代码语句简称为条件语句。如同现实生活…

【Python编程基础】第一节.Python基本语法(上)

文章目录 前言⼀、Python介绍二、Python环境配置三、Pycharm 书写代码四、Python基本语法 4.1 print 函数的简单使用 4.2 注释 4.3 Python 代码中三种波浪线和 PEP8 4.4 在 cmd 终端中运⾏ Python 代码 4.5 变量 4.6 数据类型 4.7 类型转换…

数码管的静态显示(二)

1.原理 要按照上图的顺序传递位选和段选的数据。 因为q0是最高位&#xff0c;共阳极数码管结构是dp....a&#xff0c;所以应该先传入低位a&#xff0c;而a在上图中的8段2进制编码中是seg[7]&#xff0c;所以段选信号的顺序是seg[0],...seg[7]。 因为输出信号是两个时钟&#x…

裁员潮下,打工人的自我修养

法律规定的 裁员补偿&#xff1a; 1、平等协商解除的&#xff0c;底线是N1&#xff0c;上限能谈多少法律都支持 2、有客观原因解除的&#xff0c;是N1 3、强制违法辞退的&#xff0c;是2N Tips&#xff1a;基数是每月的全额税前工资&#xff0c;包括奖金绩效等&#xff0c…

光伏电站信息化管理系统如何优化能源管理

随着可再生能源的快速发展&#xff0c;光伏电站作为其中的重要组成部分&#xff0c;其运营管理面临着越来越多的挑战。为了提升光伏电站的能源管理效率&#xff0c;信息化管理系统成为了不可或缺的工具&#xff0c;那么如何优化能源管理呢&#xff1f; 1.数据实时监控 信息化管…

GPU密集型计算性能优化的方法和技术

对GPU密集型计算进行性能优化的方法和技术多种多样。通过一些优化策略和技术需要综合考虑应用程序的具体需求、所使用的GPU硬件、以及编程模型和库的选择。通过不断地分析和调整&#xff0c;可以实现GPU计算性能的持续提升。以下是一些常用的优化策略和技术&#xff1a; 算法优…

论文阅读——EarthPT

EarthPT: a time series foundation model for Earth Observation 一个Earth Observation (EO)预训练的Transformer。EarthPT是一个7亿参数解码Transformer基础模型&#xff0c;以自回归自监督方式进行训练&#xff0c;并专门针对EO用例进行开发。我们证明了EarthPT是一个有效的…

尚硅谷vue全家桶(上)

vue2 简介第一天第二天 第三天第四天第五天 第六天第七天第八天 第九天 网课链接&#xff08;半个月拿下&#xff09; 简介 需要提前会的东西 中文文档链接点下面 vue.js 要会查文档用API 第一天 清除提示1 再文档中下载开发版本浏览器安装vue devtools插件 打开允许访问URL…

【网络编程基础(一)】网络基础和SOCKET

这里写目录标题 1、网络三要素2、IPV4和IPV6区别3、网络交互3.1、交互模型图3.2、基础通信协议3.3、OSI参考模型与TCP/IP参考模型对应关系 4、SOCKET网络套接字4.1、SOCKET分类4.2、基于流式套接字的编程流程4.3、网络通信雏形4.4、socket函数4.4.1、socket函数示例 4.5、bind函…

小红书图片怎么提取?小红书图片提取原图方法!

说到小红书&#xff0c;不少女性群体都知道这个&#xff0c;他的价值很高而且变现对于大多数做自媒体的小伙伴来说&#xff0c;也是不错的选择&#xff01; 小红书对于普通大众还是互联网创作者来说&#xff0c;都太实用了&#xff0c;唯一的缺点可能就是当我们需要存储他的图…