- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
CountDownLatch 是 Java 并发包(java.util.concurrent)中的一个同步辅助类,它允许一个或多个线程等待一组操作完成.
CountDownLatch 是基于 AQS(AbstractQueuedSynchronizer)实现的。其核心思想是维护一个倒计数,每次倒计数减少到零时,等待的线程才会继续执行。它的主要设计目标是允许多个线程协调完成一组任务.
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
构造 CountDownLatch 时传入的 count 决定了计数器的初始值。该计数器控制了线程的释放.
AQS 是 CountDownLatch 的基础,通过自定义内部类 Sync 实现,Sync 继承了 AQS 并提供了必要的方法。以下是关键操作:
acquireShared(int arg)
: 如果计数器值为零,表示所有任务已完成,线程将获得许可。releaseShared(int arg)
: 每次调用 countDown()
,会减少计数器,当计数器降到零时,AQS 将释放所有等待的线程。countDown()
:调用 releaseShared()
减少计数器,并通知等待线程。await()
:调用 acquireSharedInterruptibly(1)
,如果计数器非零则阻塞等待。CountDownLatch 的核心是基于 AbstractQueuedSynchronizer(AQS)来管理计数器状态的。AQS 是 JUC 中许多同步工具的基础,通过一个独占/共享模式的同步队列实现线程的管理和调度。CountDownLatch 采用 AQS 的共享锁机制来控制多个线程等待一个条件.
AQS 设计了两种同步模式:独占模式(exclusive)和共享模式(shared)。CountDownLatch 使用共享模式:
ReentrantLock
。Semaphore
和 CountDownLatch
。CountDownLatch 的 await() 和 countDown() 方法对应于 AQS 的 acquireShared() 和 releaseShared() 操作。acquireShared() 会检查同步状态(计数器值),若状态为零则立即返回,否则阻塞当前线程,进入等待队列。releaseShared() 用于减少计数器并唤醒所有等待线程.
CountDownLatch 通过一个私有的内部类 Sync 来实现同步逻辑。Sync 继承自 AQS,并重写 tryAcquireShared(int arg) 和 tryReleaseShared(int arg) 方法.
static final class Sync extends AbstractQueuedSynchronizer {
Sync(int count) {
setState(count);
}
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
protected boolean tryReleaseShared(int releases) {
// 自旋减计数器
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c - 1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
countDown()
减少计数器值,当计数器到达零时返回 true
,唤醒所有阻塞线程。tryReleaseShared 方法使用 CAS(compare-and-set)更新计数器,避免了锁的开销。CAS 操作由 CPU 原语(如 cmpxchg 指令)支持,实现了高效的非阻塞操作。这种设计保证了 countDown() 的线程安全性,使得多个线程能够并发地减少计数器.
CountDownLatch 不支持复用,因为 AQS 的 ConditionObject 被设计为单一触发模式。计数器一旦降至零,CountDownLatch 无法重置,只能释放所有线程,而不能再次设置初始计数器值。这就是其不可复用的根本原因.
CountDownLatch
常用于需要等待一组线程完成其任务后再继续的场景,如批处理任务。CountDownLatch
来同步各个服务的调用,并确保所有依赖服务准备好之后再执行主任务。以下示例展示如何使用 CountDownLatch 实现一个并发任务等待所有子任务完成的机制.
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
private static final int TASK_COUNT = 5;
private static CountDownLatch latch = new CountDownLatch(TASK_COUNT);
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < TASK_COUNT; i++) {
new Thread(new Task(i + 1, latch)).start();
}
// 主线程等待所有任务完成
latch.await();
System.out.println("所有任务已完成,继续主线程任务");
}
static class Task implements Runnable {
private final int taskNumber;
private final CountDownLatch latch;
Task(int taskNumber, CountDownLatch latch) {
this.taskNumber = taskNumber;
this.latch = latch;
}
@Override
public void run() {
try {
System.out.println("子任务 " + taskNumber + " 开始执行");
Thread.sleep((int) (Math.random() * 1000)); // 模拟任务执行时间
System.out.println("子任务 " + taskNumber + " 完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
latch.countDown(); // 完成一个任务,计数器减一
}
}
}
}
原理和用途:
CyclicBarrier
也允许一组线程相互等待,直到所有线程到达屏障位置(barrier point)。底层实现:
CyclicBarrier
内部通过 ReentrantLock
和 Condition
实现,屏障次数可以重置,从而支持循环使用。与 CountDownLatch 的对比:
CyclicBarrier
的可复用性使其适合重复的同步场景,而 CountDownLatch
是一次性的。CountDownLatch
更灵活,允许任意线程调用 countDown()
,适合分布式任务。CyclicBarrier
需要指定的线程达到屏障。原理和用途:
Semaphore
主要用于控制资源访问的并发数量,如限制数据库连接池的访问。底层实现:
Semaphore
基于 AQS 的共享模式实现,类似于 CountDownLatch
,但允许通过指定的“许可证”数量控制资源。与 CountDownLatch 的对比:
Semaphore
可以动态增加/减少许可,而 CountDownLatch
只能递减。Semaphore
适合控制访问限制,而 CountDownLatch
用于同步点倒计数。原理和用途:
Phaser
是 CyclicBarrier
的增强版,允许动态调整参与线程的数量。底层实现:
Phaser
内部包含一个计数器,用于管理当前阶段的参与线程,允许任务动态注册或注销。与 CountDownLatch 的对比:
Phaser
更适合复杂场景,能够灵活控制阶段和参与线程;CountDownLatch
的结构简单,只能用于一次性同步。Phaser
的设计更复杂,适合长时间、多线程协调任务,而 CountDownLatch
更适合简单任务等待。CountDownLatch 是一个轻量级、不可复用的倒计数同步器,适合简单的一次性线程协调。其基于 AQS 的共享锁实现使得线程等待和计数器更新具有高效的并发性。虽然 CountDownLatch 不具备重用性,但其设计简洁,尤其适合需要等待多线程任务完成的场景.
与其他 JUC 工具相比:
CyclicBarrier
更适合多阶段同步、阶段性汇总任务。Semaphore
适合资源访问控制,具有可控的许可量。Phaser
灵活性更高,适合动态参与线程、复杂多阶段任务。选择适合的同步工具,取决于任务的性质、线程参与动态性以及是否需要重用同步控制.
最后此篇关于一文彻底弄懂JUC工具包的CountDownLatch的设计理念与底层原理的文章就讲到这里了,如果你想了解更多关于一文彻底弄懂JUC工具包的CountDownLatch的设计理念与底层原理的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我有以下功能: function addChange(result, bill) { for (var i=0;i
这是网站: www.wearethefirehouse.com/phasetest 如果您慢慢滚动,您会注意到一旦菜单栏完全不透明,nav li 元素就会全部从 Enzo 300 跳起来(如在没有导航
美好的一天。对于当前的项目,我需要知道数据类型如何表示为字节。例如,如果我使用: long three = 500;var bytes = BitConverter.GetBytes(three);
请解释 JVM 是如何在底层收集 ThreadDump 的。 我不明白它如何收集脱离 CPU 的线程的堆栈跟踪(等待磁盘 IO、网络、非自愿上下文切换)。 例如,linux perf 仅收集有关 on
开始学习 R,如果能帮助我理解 R 如何决定不同向量的类别,我将不胜感激。我初始化 vec <- c(1:6)当我执行 class(vec)我得到“整数”。为什么它不是“数字”,因为我认为 R 中的整
我有一个透明的 UIView,几乎覆盖了整个屏幕。我在顶部留下了 50 像素。它是 View Controller View 的 subview 。 在UIView下面有一个继承自UIView的MyV
我很好奇对象是如何在 Nodejs 中显示的,在本例中是 Promise。使用 console.log(promiseObject) 时,输出的类型为 {状态:待处理} 这对我来说似乎很奇怪,因为在该
当您在 Windows Azure 中使用表服务 API 时,幕后到底在做什么?我想我在某处读到这没有使用 SQL Server。它是否执行哈希表,然后过滤器真的像映射/减少操作一样运行?我对这些东西
如何查看函数 concat 中的代码?它是如何做的?有没有人有代码的副本或在浏览器控制台中查看它的方法? console.dir 不给我访问权限 console.dir(Array.prototype
我是 C++ 的新手,所以如果这个问题的答案显而易见,我深表歉意。 我一直在编写 STL 样式的自定义数据结构,以此来提高我的技能。 (我实际上也确实需要这种结构,但出于学习目的,我有点过分了。) 此
我正在尝试使用 log4j appender 将日志发送到 GrayLog2 (log4j2-gelf)。所以我将我的依赖项添加到我的 pom.xml 配置 log4j2.xml 来配置我的 appe
我正在使用带有 vector 的 priority_queue 作为底层容器。但是我希望堆的大小非常大。我知道动态 vector 容量调整大小的问题。所以我正在寻找方法来为我的priority_que
我有一个 SqlDataAdapter,它填充了 21 行数据(4 列)。驱动它的 sproc 在几秒钟内在 SQL Mgmt Studio 中返回,但 .Fill() 需要 5 分钟。 Ar
我想实现一个屏幕控制按钮,按下它可以作为 GUI 交互的修饰符。 这对于 MouseArea 是不可能的,因为该 API 只能处理一个鼠标区域中的一个触摸点。 该限制不适用于 MultiPointTo
我试图将图像和 div 层置于包含 div 的中心,但到目前为止我无法让它从列的左侧移动。我尝试了几种不同的方法,但就是无法让它移动。即使 margin auto 技巧也不起作用,我怀疑这是因为 bo
需要明确的是,我不是在询问 HDFS 中的权限设置,而是在 ext3 中或在 HDFS 运行于其上的各个数据节点机器上使用的任何文件系统中。 p> 我知道我们设置了 sudo chown hduser
我在服务器上创建了一个枚举,其中手动设置了整数值,而不是默认从 0 开始递增 public enum UserType { Anonymous = 0, Customer = 10,
如果显示框架图像,我们能否使以下 Google map 具有交互性。 Vie
我有一个顶部有自定义状态栏的布局 [在 Apple 的状态栏下方],然后是 UIScrollview 在中间部分从左到右分页,然后我有一个 UIView 底部有一些自定义按钮。一个简单的三 Pane
事情是这样的。我有一个 MVC 操作,在该操作上,我应用了自定义 ActionFilterAttribute 来使反序列化工作。现在,我想要做的是根据在此 View 中设置的 ViewBag.Titl
我是一名优秀的程序员,十分优秀!