【并发编程学习篇】深入理解CountDownLatch

news/2024/4/26 4:39:38/文章来源:https://blog.csdn.net/qq_42285585/article/details/129240899

一、CountDownLatch介绍

  1. CountDownLatch(闭锁)是一个同步协助类,允许一个或多个线程等待,直到其他线程完成操作集。
  2. CountDownLatch使用给定的计数值(count)初始化。
  3. await方法会阻塞直到当前的计数值被countDown方法的调用达到0,count为0之后所有等待的线程都会被释放,并且随后对await方法的调用都会立即返回。
  4. 这是一个一次性现象 —— count不会被重置。如果你需要一个重置count的版本,那么请考虑使用CyclicBarrier。

二、CountDownLatch的使用

在这里插入图片描述

构造器
在这里插入图片描述

2.1 常用方法

 // 调用 await() 方法的线程会被挂起,它会等待直到 count 值为 0 才继续执行
public void await() throws InterruptedException { };  
// 和 await() 类似,若等待 timeout 时长后,count 值还是没有变为 0,不再等待,继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  
// 会将 count 减 1,直至为 0

三、CountDownLatch应用场景

CountDownLatch一般用作多线程倒计时计数器,强制它们等待其他一组(CountDownLatch的初始化决定)任务执行完成。

CountDownLatch的两种使用场景:

  • 场景1:让多个线程等待
  • 场景2:让单个线程等待。

3.1 场景1 让多个线程等待:模拟并发,让并发线程一起执行

public class CountDownLatchTest {public static void main(String[] args) throws InterruptedException {CountDownLatch countDownLatch = new CountDownLatch(1);for (int i = 0; i < 5; i++) {new Thread(() -> {try {//准备完毕……运动员都阻塞在这,等待号令countDownLatch.await();String parter = "【" + Thread.currentThread().getName() + "】";System.out.println(parter + "开始执行……");} catch (InterruptedException e) {e.printStackTrace();}}).start();}Thread.sleep(2000);// 裁判准备发令countDownLatch.countDown();// 发令枪:执行发令}

3.2 场景2 让单个线程等待:多个线程(任务)完成后,进行汇总合并

  1. 很多时候,我们的并发任务,存在前后依赖关系;
  2. 比如数据详情页需要同时调用多个接口获取数据,并发请求获取到数据后、需要进行结果合并;
  3. 或者多个数据操作完成后,需要数据check;这其实都是:在多个线程(任务)完成后,进行汇总合并的场景。
public class CountDownLatchTest2 {public static void main(String[] args) throws Exception {CountDownLatch countDownLatch = new CountDownLatch(5);for (int i = 0; i < 5; i++) {final int index = i;new Thread(() -> {try {Thread.sleep(1000 + ThreadLocalRandom.current().nextInt(1000));System.out.println(Thread.currentThread().getName()+" finish task" + index );countDownLatch.countDown();} catch (InterruptedException e) {e.printStackTrace();}}).start();}// 主线程在阻塞,当计数器==0,就唤醒主线程往下执行。countDownLatch.await();System.out.println("主线程:在所有任务运行完成后,进行结果汇总");}

四、CountDownLatch实现原理

  1. 底层基于 AbstractQueuedSynchronizer 实现,CountDownLatch 构造函数中指定的count直接赋给AQS的state;
  2. 每次countDown()计数器值减一,最后减到0时unpark阻塞线程;这一步是由最后一个执行countdown方法的线程执行的。
  3. 而调用await()方法时,当前线程就会判断state属性是否为0,如果为0,则继续往下执行,如果不为0,则使当前线程进入等待状态,直到某个线程将state属性置为0,其就会唤醒在await()方法中等待的线程。

4.1 CountDownLatch与Thread.join的区别

  1. CountDownLatch的作用就是允许一个或多个线程等待其他线程完成操作,看起来有点类似join() 方法,但其提供了比 join() 更加灵活的API。

  2. CountDownLatch可以手动控制在n个线程里调用n次countDown()方法使计数器进行减一操作,也可以在一个线程里调用n次执行减一操作。

  3. 而 join() 的实现原理是不停检查join线程是否存活,如果 join 线程存活则让当前线程永远等待。所以两者之间相对来说还是CountDownLatch使用起来较为灵活。

五、CountDownLatch核心源码分析

5.1 从构造方法查看

// CountDownLatch 的有参构造
public CountDownLatch(int count) {// 健壮性校验if (count < 0) throw new IllegalArgumentException("count < 0");// 构建Sync给AQS的state赋值this.sync = new Sync(count);
}

5.2 countDown方法

// countDown方法,本质就是调用了AQS的释放共享锁操作
// 这里的功能都是AQS提供的,只有tryReleaseShared需要实现的类自己去编写业务
public final boolean releaseShared(int arg) {if (tryReleaseShared(arg)) {// 唤醒在AQS队列中排队的线程。doReleaseShared();return true;}return false;
}// countDownLatch实现的业务
protected boolean tryReleaseShared(int releases) {for (;;) {int c = getState();if (c == 0)return false;// state - 1int nextc = c-1;// 用CAS赋值if (compareAndSetState(c, nextc))return nextc == 0;}
}
// 如果CountDownLatch中的state已经为0了,那么再次执行countDown跟没执行一样。
// 而且只要state变为0,await就不会阻塞线程。

5.3 await方法

// await方法
public void await() throws InterruptedException {// 调用了AQS提供的获取共享锁并且允许中断的方法sync.acquireSharedInterruptibly(1);
}// AQS提欧的获取共享锁并且允许中断的方法
public final void acquireSharedInterruptibly(int arg)throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();// countDownLatch操作if (tryAcquireShared(arg) < 0)// 如果返回的是-1,代表state肯定大于0doAcquireSharedInterruptibly(arg);
}// CountDownLatch实现的tryAcquireShared
protected int tryAcquireShared(int acquires) {// state为0,返回1,。否则返回-1return (getState() == 0) ? 1 : -1;
}// 让当前线程进到AQS队列,排队去
private void doAcquireSharedInterruptibly(int arg) throws InterruptedException {// 将当前线程封装为Node,并且添加到AQS的队列中final Node node = addWaiter(Node.SHARED);boolean failed = true;try {for (;;) {final Node p = node.predecessor();if (p == head) {// 再次走上面的tryAcquireShared,如果返回的是的1,代表state为0int r = tryAcquireShared(arg);if (r >= 0) {// 会将当前线程和后面所有排队的线程都唤醒。setHeadAndPropagate(node, r);p.next = null; // help GCfailed = false;return;}}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())throw new InterruptedException();}} finally {if (failed)cancelAcquire(node);}
}

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

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

相关文章

只需四步,手把手教你打造专属数字人

伴随ChatGPT的问世&#xff0c;在技术与商业运作上都日渐发展成熟的数字人产业正持续升温。去年9月&#xff0c;北京市发布了国内首个数字人产业专项支持政策&#xff0c;提出将依托国家文化专网将数字人纳入文化数据服务平台。以数字人、ChatGPT为代表的互联网3.0创新应用产业…

kali下安装Volatility

一、About Volatility Volatility是一款开源内存取证框架&#xff0c;能够对导出的内存镜像进行分析&#xff0c;通过获取内核数据结构&#xff0c;使用插件获取内存的详细情况以及系统的运行状态。 Volatility是一款非常强大的内存取证工具,它是由来自全世界的数百位知名安全…

FAST‘23《λ-IO: A Unified IO Stack for Computational Storage》论文解读

FAST’23《λ-IO: A Unified IO Stack for Computational Storage》论文解读 Data:2023-2-27 Ref: Z. Yang et al., “λ-IO: A Unified IO Stack for Computational Storage,” in 21st USENIX Conference on File and Storage Technologies (FAST 23), Santa Clara, CA, Feb.…

数据可视化第二版-03部分-06章-比较与排序

文章目录数据可视化第二版-03部分-06章-比较与排序总结可视化视角-比较与排序代码实现创建虚拟环境1. python版本管理2.切换到指定版本后安装虚拟环境切换路径到文件当前路径柱形图环形柱状图子弹图哑铃图雷达图词云图教材截图数据可视化第二版-03部分-06章-比较与排序 总结 …

Java 多线程 --- 多线程的相关概念

Java 多线程 --- 多线程的相关概念Race Condition 问题并发编程的性质 --- 原子性, 可见性, 有序性上下文切换 (Context Switch)线程的一些故障 --- 死锁, 活锁, 饥饿死锁 (Deadlock)活锁(Livelock)死锁和活锁的区别饥饿(Starvation)背景: 操作系统 — 线程/进程 同步 Race Co…

【unity学习记录】Canvas Group组件

&#x1f497; 未来的游戏开发程序媛&#xff0c;现在的努力学习菜鸡 &#x1f4a6;本专栏是我关于游戏开发的学习笔记 &#x1f236;本篇是unity的Canvas Group组件 Canvas Group画布组介绍详解1. Alpha2. Interactable3. Blocks Raycasts4. Ignore Parent Groups介绍 画布组…

6.0.4:GrapeCity Documents for Excel GcExcel Crack

在更短的时间内生成 Excel 电子表格&#xff0c;不依赖于 Excel&#xff01; 在任何应用程序中转换、计算、格式化和解析电子表格。 快速高效&#xff1a;其轻巧的尺寸意味着 Documents for Excel 针对快速处理大型 Excel 文档进行了优化 使用适用于 Windows、Linux 和 Mac 的…

JVM 学习(2)—简单理解强、软、弱、虚 Java 四大引用

一、Java 引用概述 Java 中出现四种引用是为了更加灵活地管理对象的生命周期&#xff0c;以便在不同场景下灵活地处理对象的回收问题。不同类型的引用在垃圾回收时的处理方式不同&#xff0c;可以用来实现不同的垃圾回收策略。Java 目前将其分成四类&#xff0c;类图如下&…

mysql一两种索引方式hash和btree

1. Hash索引&#xff1a; Hash 索引结构的特殊性&#xff0c;其检索效率非常高&#xff0c;索引的检索可以一次定位&#xff0c;不像B-Tree 索引需要从根节点到枝节点&#xff0c;最后才能访问到页节点这样多次的IO访问&#xff0c;所以 Hash 索引的查询效率要远高于 B-Tree 索…

信息安全概论之《密码编码学与网络安全----原理与实践(第八版)》

前言&#xff1a;在信息安全概论课程的学习中&#xff0c;参考了《密码编码学与网络安全----原理与实践&#xff08;第八版&#xff09;》一书。以下内容为以课件为主要参考&#xff0c;课本内容与网络资源为辅助参考&#xff0c;学习该课程后作出的总结。 一、信息安全概述 1…

力扣Top100题之两数相加(Java解法)

0 题目描述 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff0c;这两个数…

MVCC 当前读 快照读 RC read view RR下事务更新不会丢失

MVCC(multi-version-concurrent-control) MVCC是行锁的一个变种&#xff0c;但MVCC在很多情况下它避免了加锁。不是buffer块&#xff0c;而是buffer中的记录行。 MVCC (Multi-Version Concurrency Control) (注&#xff1a;与MVCC相对的&#xff0c;是基于锁的并发控制&#x…

【无限思维画布】制作思维导图第五步,节点创建与连接,拖拽对齐与双击缩放

正在为无限词典制作单词思维导图功能&#xff0c;实现无限单词导图&#xff0c;无限思维画布。目前制作到第五步&#xff0c;实现节点创建、节点连接、节点拖拽对齐&#xff1a; 节点创建与连接&#xff0c;拖拽对齐Details 第四步&#xff0c;推倒重来。 一开始受vue-mindma…

【Python小程序】这款成语接龙小程序,让小孩儿轻松记住500个成语,在家里常玩,语文直上135,仅此一份,快收藏~(太强大了)

前言 学习路上&#xff0c;那我同行。 哈喽~大家晚上好呀&#xff0c;我是你们的栗子同学。 所有文章完整的素材源码都在&#x1f447;&#x1f447; 粉丝白嫖源码福利&#xff0c;请移步至CSDN社区或文末公众hao即可免费。 成语接龙是一个传统的文字游戏。很多孩子都喜欢玩。…

Lesson9---回归问题

9.1 机器学习基础 课程回顾 Python语言基础Numpy/Matplotlib/Pandas/Pillow应用TensorFlow2.0 低阶API 即将学习 机器学习、人工神经网络、深度学习、卷积神经网络典型模型的TensorFlow2.0实现 9.1.1 机器学习 机器学习&#xff08;Machine Learning&#xff09;&#xf…

关于C语言中最大公因数的思考

目录 如何去求最大公因数利用枚举法&#xff1a; 如何去求最大公因数利用辗转相除法&#xff1a; 例1&#xff1a;最大公因数使用for循环和if语句 示例2&#xff1a;最大公因数使用while循环和if ... else语句 例3&#xff1a;正负数均为最大公因数 如何去求最大公因数利用…

【2023-02-27】349.两个数组的交集

题目链接&#xff1a;349.两个数组的交集 解题思路&#xff1a;点我 class Solution { public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {unordered_set<int>res_set;unordered_set<int>nums1_set(nums1.beg…

qt-c++进阶1-window、linux下获取本机所有网卡ip信息、根据网卡名获取ip地址。

系列文章目录 例如&#xff1a;第一章 主要是通过qt-c实现获取本机电脑的网卡信息或者是IP信息 文章目录系列文章目录前言一、获取本机网卡IP信息1.1 获取ip地址方法1.2 代码实例总结前言 总结c获取本机网卡信息的方法 第一章&#xff1a;适用于windows操作系统、linux操作系…

Aspose.Slides for .NET 授权须知

Aspose.Slides是一款用于生成&#xff0c;管理和转换PowerPoint幻灯片的本机API&#xff0c;可以使用多种格式&#xff0c;而不需要Microsoft PowerPoint。并且可在任何平台上操作PowerPoint演示文稿。 Aspose.Slides for .NET是一款.NET PowerPoint管理API&#xff0c;用于读…

常用逻辑运算符

逻辑符号表格 逻辑符号含义描述&按位与将数字转成二进制计算&#xff0c;两个位都为1时&#xff0c;结果才为1|或两个位都为0时&#xff0c;结果才为0 &#xff0c;反知任何一个为1结果为1^异或两个位相同为0&#xff0c;不同为1<<左移整体二进位全部左移若干位&…