当前位置: 首页 > news >正文

java CountDownLatch和CyclicBarrier

专栏系列文章地址:https://blog.csdn.net/qq_26437925/article/details/145290162

本文目标:

  1. 理解CountDownLatch和CyclicBarrier的使用,主要是复习Aqs

另外工作中用到CountDownLatch的地方还很多,一般是完成某些事情才能继续某项操作

  • 单词1: countdown
常见释义:[ˈkaʊntdaʊn][ˈkaʊntdaʊn]
n.	倒数读秒,倒计时(如发射宇宙飞船时); 大事临近的时期;
[例句]The countdown to Christmas starts here.
现在开始圣诞节倒计时。
[其他]	复数:countdowns
  • 单词2: latch
常见释义 英[lætʃ][lætʃ]
n.	插销; 门闩; 弹簧锁; 碰锁;
vt.	用插销插上; 用碰锁锁上;
[例句]He lifted the latch and opened the door.
他拉起门闩开了门。
[其他]	第三人称单数:latches 复数:latches 现在分词:latching 过去式:latched 过去分词:latched

目录

  • CountDownLatch (做减法,例子:六国逐一灭,秦统一)
    • CountDownLatch源码
      • countDownLatch.countDown()
      • countDownLatch.await()
  • CyclicBarrier(做加法,例子:召唤神龙,要收集到七龙珠)

CountDownLatch (做减法,例子:六国逐一灭,秦统一)

A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

public class Main {public static void main(String[] args) throws Exception {CountDownLatch countDownLatch = new CountDownLatch(6);for (int i = 1; i <= 6; i++) {new Thread(() -> {System.out.println(Thread.currentThread().getName() + "国,被灭");countDownLatch.countDown(); // count 减一}, "" + i).start();}// 一直等待,直到数字达到0,放行。countDownLatch.await();System.out.println(Thread.currentThread().getName() + "\t **************秦帝国,统一华夏");closeDoor();}private static void closeDoor() throws InterruptedException {CountDownLatch countDownLatch = new CountDownLatch(6);for (int i = 1; i <= 6; i++) {new Thread(()->{System.out.println(Thread.currentThread().getName()+"\t上完自习,离开教室");countDownLatch.countDown();}, "thread"+String.valueOf(i)).start();}// 等待,减少数字达到0,放行。countDownLatch.await();System.out.println(Thread.currentThread().getName()+"\t **************班长最后关门走人");}
}

CountDownLatch源码

自定义Sync类继承AbstractQueuedSynchronizer,利用AQS自身的状态变量state代表数量(初始化的时候指定),countdown操作让状态只减1(具体是CAS操作compareAndSetState方法让state减少1)

public class CountDownLatch {/*** Synchronization control For CountDownLatch.* Uses AQS state to represent count.*/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 zerofor (;;) {int c = getState();if (c == 0)return false;int nextc = c-1;if (compareAndSetState(c, nextc))return nextc == 0;}}}private final Sync sync;public void countDown() {sync.releaseShared(1);}
  • unsafe.compareAndSwapInt方法
/*** Atomically sets synchronization state to the given updated* value if the current state value equals the expected value.* This operation has memory semantics of a {@code volatile} read* and write.** @param expect the expected value* @param update the new value* @return {@code true} if successful. False return indicates that the actual*         value was not equal to the expected value.*/
protected final boolean compareAndSetState(int expect, int update) {// See below for intrinsics setup to support thisreturn unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

countDownLatch.countDown()

在这里插入图片描述

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

使用了Aqs的releaseShared方法

/*** Releases in shared mode.  Implemented by unblocking one or more* threads if {@link #tryReleaseShared} returns true.** @param arg the release argument.  This value is conveyed to*        {@link #tryReleaseShared} but is otherwise uninterpreted*        and can represent anything you like.* @return the value returned from {@link #tryReleaseShared}*/
public final boolean releaseShared(int arg) {// 如果 tryReleaseShared 返回 false,则 releaseShared 返回false// 如果 tryReleaseShared 返回 true, 执行 doReleaseSharedif (tryReleaseShared(arg)) {doReleaseShared();return true;}return false;
}
  • countDownLatch 的tryReleaseShared方法:不断的while循环CAS操作让state减少1,如果成功就返回true;如果state已经等于0了,就直接返回false
protected boolean tryReleaseShared(int releases) {// Decrement count; signal when transition to zerofor (;;) {int c = getState();if (c == 0)return false;int nextc = c-1;if (compareAndSetState(c, nextc))return nextc == 0;}
}
  • aqs的doReleaseShared方法
  1. doReleaseShared会尝试唤醒head后继的代表线程,如果线程已经唤醒,则仅仅设置PROPAGATE状态
  2. 步骤一的“尝试唤醒head后继的代表线程”和“设置PROPAGATE状态”都是CAS操作,如果CAS失败,则会循环再次尝试
/**
* Release action for shared mode -- signals successor and ensures
* propagation. (Note: For exclusive mode, release just amounts
* to calling unparkSuccessor of head if it needs signal.)
*/
private void doReleaseShared() {/** Ensure that a release propagates, even if there are other* in-progress acquires/releases.  This proceeds in the usual* way of trying to unparkSuccessor of head if it needs* signal. But if it does not, status is set to PROPAGATE to* ensure that upon release, propagation continues.* Additionally, we must loop in case a new node is added* while we are doing this. Also, unlike other uses of* unparkSuccessor, we need to know if CAS to reset status* fails, if so rechecking.*/for (;;) {Node h = head;if (h != null && h != tail) {int ws = h.waitStatus;if (ws == Node.SIGNAL) {if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))continue;            // loop to recheck casesunparkSuccessor(h);}else if (ws == 0 &&!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))continue;                // loop on failed CAS}if (h == head)                   // loop if head changedbreak;}
}

countDownLatch.await()

在这里插入图片描述

/**当前线程一直等待直到countDown到0,或者线程有interrupted异常抛出;如果count本来就是0,那么该方法直接返回* Causes the current thread to wait until the latch has counted down to
* zero, unless the thread is {@linkplain Thread#interrupt interrupted}.
*
* <p>If the current count is zero then this method returns immediately.
*
* <p>If the current count is greater than zero then the current
* thread becomes disabled for thread scheduling purposes and lies
* dormant until one of two things happen:
* <ul>
* <li>The count reaches zero due to invocations of the
* {@link #countDown} method; or
* <li>Some other thread {@linkplain Thread#interrupt interrupts}
* the current thread.
* </ul>
*
* <p>If the current thread:
* <ul>
* <li>has its interrupted status set on entry to this method; or
* <li>is {@linkplain Thread#interrupt interrupted} while waiting,
* </ul>
* then {@link InterruptedException} is thrown and the current thread's
* interrupted status is cleared.
*
* @throws InterruptedException if the current thread is interrupted
*         while waiting
*/
public void await() throws InterruptedException {sync.acquireSharedInterruptibly(1);
}public final void acquireSharedInterruptibly(int arg)throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();if (tryAcquireShared(arg) < 0)doAcquireSharedInterruptibly(arg);
}
  • CountdownLatch的tryAcquireShared方法:如果state==0返回1,否则返回-1;所以只要state不是0,if (tryAcquireShared(arg) < 0)条件就成立,则执行doAcquireSharedInterruptibly方法
protected int tryAcquireShared(int acquires) {return (getState() == 0) ? 1 : -1;
}
  • Aqs的doAcquireSharedInterruptibly方法

用当前线程构造一个共享模式Node,然后CAS操作加入CLH队列尾部,接着仍然是while(true)判断tryAcquireShared(arg),一定要是返回1,才会return,否则就是判断node的前驱节点,然后判断tryAcquireShared(arg)判断

/**
* Acquires in shared interruptible mode.
* @param arg the acquire argument
*/
private void doAcquireSharedInterruptibly(int arg)throws InterruptedException {// 添加共享模式节点,final Node node = addWaiter(Node.SHARED);boolean failed = true;try {for (;;) {// 拿到当前节点的前驱节点final Node p = node.predecessor();if (p == head) {// 尝试获取资源int r = tryAcquireShared(arg);// 大于等于0,说明有资源获取if (r >= 0) {// 把当前节点设置成head节点,并传播唤醒后面的节点。setHeadAndPropagate(node, r);p.next = null; // help GCfailed = false;return;}}// 这里和独占模式一样,如果没资源申请,封装节点,并park等待if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())throw new InterruptedException();}} finally {if (failed)cancelAcquire(node);}
}

CyclicBarrier(做加法,例子:召唤神龙,要收集到七龙珠)

A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point. CyclicBarriers are useful in programs involving a fixed sized party of threads that must occasionally wait for each other. The barrier is called cyclic because it can be re-used after the waiting threads are released.

  • cyclic: adj. 循环的; 周期的;
  • barrier: n. 屏障; 障碍物; 障碍; 阻力; 关卡; 分界线; 隔阂;
public class Main {public static void main(String[] args) {CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{System.out.println("****召唤神龙****");});for (int i = 1; i <= 7; i++) {final int tempInt = i;new Thread(()->{System.out.println(Thread.currentThread().getName()+"\t收集到第七颗龙珠:"+tempInt+"龙珠");try {cyclicBarrier.await(); // 找到了,就继续等其它龙珠收集} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}}, String.valueOf(i)).start();}}}

相关文章:

java CountDownLatch和CyclicBarrier

专栏系列文章地址&#xff1a;https://blog.csdn.net/qq_26437925/article/details/145290162 本文目标&#xff1a; 理解CountDownLatch和CyclicBarrier的使用&#xff0c;主要是复习Aqs 另外工作中用到CountDownLatch的地方还很多&#xff0c;一般是完成某些事情才能继续某…...

力扣动态规划-17【算法学习day.111】

前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;建议灵神的题单和代码随想录&#xff09;和记录自己的学习过程&#xff0c;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关…...

读书笔记-《你的灯亮着吗?》

这是一本短篇且有趣的书&#xff0c;通过一些小故事讨论了下解决问题时会遇到的困难。 01 为什么难以定义问题 常言道&#xff0c;办法总比问题多&#xff0c;但往往我们在一开始就没有定义好问题&#xff1a; 在学校时&#xff0c;校园教育使得我们会紧紧抓住看起来像是“问题…...

MATLAB实现多种群遗传算法

多种群遗传算法&#xff08;MPGA, Multi-Population Genetic Algorithm&#xff09;是一种改进的遗传算法&#xff0c;它通过将种群分成多个子种群并在不同的子种群之间进行交叉和交换&#xff0c;旨在提高全局搜索能力并避免早期收敛。下面是多种群遗传算法的主要步骤和流程&a…...

tf.Keras (tf-1.15)使用记录3-model.compile方法

model.compile 是 TensorFlow Keras 中用于配置训练模型的方法。在开始训练之前&#xff0c;需要通过这个方法来指定模型的优化器、损失函数和评估指标等。 注意事项: 在开始训练&#xff08;调用 model.fit&#xff09;之前&#xff0c;必须先调用 model.compile()。 1 基本…...

Prometheus 中的 Exporter

在 Prometheus 生态系统中,Exporter 扮演着至关重要的角色,它们负责从不同的服务或系统中收集和暴露度量数据。本文将详细介绍 Exporter 的概念、类型以及如何有效使用它们将 Prometheus 集成到各种系统中进行监控。 什么是 Exporter? Exporter 是一段软件,它从应用程序或…...

网工_HDLC协议

2025.01.25&#xff1a;网工老姜学习笔记 第9节 HDLC协议 9.1 HDLC高级数据链路控制9.2 HDLC帧格式&#xff08;*控制字段&#xff09;9.2.1 信息帧&#xff08;承载用户数据&#xff0c;0开头&#xff09;9.2.2 监督帧&#xff08;帮助信息可靠传输&#xff0c;10开头&#xf…...

leetcode 2563. 统计公平数对的数目

题目如下 数据范围 显然数组长度最大可以到10的5次方n方的复杂度必然超时&#xff0c;阅读题目实际上就是寻找两个位置不同的数满足不等式即可(实际上i j无所谓是哪个 我们只要把位置小的想成i就行)。 按照上面的思路我们只需要排序数组然后从前往后遍历数组然后利用二分查找…...

Debian 10 中 Linux 4.19 内核在 x86_64 架构上对中断嵌套的支持情况

一、中断嵌套的定义与原理 中断嵌套是指在一个中断处理程序(ISR)正在执行的过程中,另一个更高优先级的中断请求到来,系统暂停当前中断处理程序,转而处理新的高优先级中断。处理完高优先级中断后,系统返回到原来的中断处理程序继续执行。这种机制允许系统更高效地响应紧急…...

FLTK - FLTK1.4.1 - demo - bitmap

文章目录 FLTK - FLTK1.4.1 - demo - bitmap概述笔记END FLTK - FLTK1.4.1 - demo - bitmap 概述 // 功能 : 演示位图数据在按钮上的显示 // * 以按钮为范围或者以窗口为范围移动 // * 上下左右, 文字和图像的相对位置 // 失能按钮&#xff0c;使能按钮 // 知识点 // FLTK可…...

数据结构 树1

目录 前言 一&#xff0c;树的引论 二&#xff0c;二叉树 三&#xff0c;二叉树的详细理解 四&#xff0c;二叉搜索树 五&#xff0c;二分法与二叉搜索树的效率 六&#xff0c;二叉搜索树的实现 七&#xff0c;查找最大值和最小值 指针传递 vs 传引用 为什么指针按值传递不会修…...

android主题设置为..DarkActionBar.Bridge时自定义DatePicker选中日期颜色

安卓自定义DatePicker选中日期颜色 背景&#xff1a;解决方案&#xff1a;方案一&#xff1a;方案二&#xff1a;实践效果&#xff1a; 背景&#xff1a; 最近在尝试用原生安卓实现仿element-ui表单校验功能&#xff0c;其中的的选择日期涉及到安卓DatePicker组件的使用&#…...

MySQL 如何深度分页问题

在实际的数据库应用场景中&#xff0c;我们常常会遇到需要进行分页查询的需求。对于少量数据的分页查询&#xff0c;MySQL 可以轻松应对。然而&#xff0c;当我们需要进行深度分页&#xff08;即从大量数据的中间位置开始获取少量数据&#xff09;时&#xff0c;就会面临性能严…...

1.攻防世界easyphp

进入题目页面如下 是一段PHP代码进行代码审计 <?php // 高亮显示PHP文件源代码 highlight_file(__FILE__);// 初始化变量$key1和$key2为0 $key1 0; $key2 0;// 从GET请求中获取参数a的值&#xff0c;并赋值给变量$a $a $_GET[a]; // 从GET请求中获取参数b的值&#xff…...

深度学习 Pytorch 神经网络的学习

本节将从梯度下降法向外拓展&#xff0c;介绍更常用的优化算法&#xff0c;实现神经网络的学习和迭代。在本节课结束将完整实现一个神经网络训练的全流程。 对于像神经网络这样的复杂模型&#xff0c;可能会有数百个 w w w的存在&#xff0c;同时如果我们使用的是像交叉熵这样…...

如何利用天赋实现最大化的价值输出-补

原文&#xff1a; https://blog.csdn.net/ZhangRelay/article/details/145408621 ​​​​​​如何利用天赋实现最大化的价值输出-CSDN博客 如何利用天赋实现最大化的价值输出-CSDN博客 引用视频差异 第一段视频目标明确&#xff0c;建议也非常明确。 录制视频的人是主动性…...

Vue简介

目录 Vue是什么&#xff1f;为什么要使用Vue&#xff1f;Vue的三种加载方式拓展&#xff1a;什么是渐进式框架&#xff1f; Vue是什么&#xff1f; Vue是一套用于构建用户界面的渐进式 JavaScript (主张最少)框架 &#xff0c;开发者只需关注视图层。另一方面&#xff0c;当与…...

three.js+WebGL踩坑经验合集(6.2):负缩放,负定矩阵和行列式的关系(3D版本)

本篇将紧接上篇的2D版本对3D版的负缩放矩阵进行解读。 (6.1):负缩放&#xff0c;负定矩阵和行列式的关系&#xff08;2D版本&#xff09; 既然three.js对3D版的负缩放也使用行列式进行判断&#xff0c;那么&#xff0c;2D版的结论用到3D上其实是没毛病的&#xff0c;THREE.Li…...

使用 OpenResty 构建高效的动态图片水印代理服务20250127

使用 OpenResty 构建高效的动态图片水印代理服务 在当今数字化的时代&#xff0c;图片在各种业务场景中广泛应用。为了保护版权、统一品牌形象&#xff0c;动态图片水印功能显得尤为重要。然而&#xff0c;直接在后端服务中集成水印功能&#xff0c;往往会带来代码复杂度增加、…...

Kafka下载

一、Kafka下载 下载地址&#xff1a;https://kafka.apache.org/downloads 二、Kafka安装 因为选择下载的是 .zip 文件&#xff0c;直接跳过安装&#xff0c;一步到位。 选择在任一磁盘创建空文件夹&#xff08;不要使用中文路径&#xff09;&#xff0c;解压之后把文件夹内容…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别

UnsatisfiedLinkError 在对接硬件设备中&#xff0c;我们会遇到使用 java 调用 dll文件 的情况&#xff0c;此时大概率出现UnsatisfiedLinkError链接错误&#xff0c;原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用&#xff0c;结果 dll 未实现 JNI 协…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...