CountDownLatch基本使用及原理

news2024/11/16 9:28:22

CountDownLatch基本使用及原理

  • 一、CountDownLatch简介
  • 二、CountDownLatch类的继承关系
    • 1. AbstractQueuedSynchronizer: 用于构建锁和同步器的框架。
    • 2. Sync: CountDownLatch的内部类,提供了锁的具体实现。
  • 三、Semaphore的基本使用
    • 1. 使用场景:
    • 2. 代码实现:
    • 3. 运行结果:
    • 4. 案例分析:
  • 四、CountDownLatch的优缺点
    • 1. 优点:
      • 1.1、简单易用:
      • 1.2、灵活性高:
      • 1.3、线程安全:
    • 2. 缺点:
      • 2.1、只能倒数一次:
      • 2.2、不支持中断:
      • 2.3、异常处理困难:
    • 3. 小结:
  • 五、底层原理分析
    • 1. await()方法:
    • 2. countDown()方法:

一、CountDownLatch简介

  1. CountDownLatch是一个线程同步工具类,它可以让一个或多个线程等待其他线程完成某个任务后再继续执行。它通过一个计数器来实现,计数器的初始值可以设置为一个正整数,每当一个线程完成任务后,计数器的值就会减1,当计数器的值变为0时,所有等待的线程就会被唤醒。

二、CountDownLatch类的继承关系

countdownlatch

1. AbstractQueuedSynchronizer: 用于构建锁和同步器的框架。

AbstractQueuedSynchronizer是一个用于构建锁和同步器的基类,它提供了一个框架,供子类重写并实现自己的同步逻辑。AQS内部维护了一个FIFO的等待队列,用于管理等待获取锁的线程,并提供了一些方法供子类操作这个队列。通过继承AQS,可以方便地实现各种同步机制。

2. Sync: CountDownLatch的内部类,提供了锁的具体实现。

Sync是CountDownLatch的内部类,它继承自AbstractQueuedSynchronizer(AQS),用于实现CountDownLatch的同步机制。Sync通过继承AQS,实现了AQS的共享模式,来控制多个线程之间的同步。

三、Semaphore的基本使用

1. 使用场景:

CountDownLatch 是 Java 中的一个同步工具类,可以用来实现线程之间的等待。在玩王者荣耀时,如果需要等待队友都准备好后才能开始游戏,可以使用 CountDownLatch 来实现。
wangzhe

2. 代码实现:

  1. 首先,创建一个 CountDownLatch 对象,将其计数器初始化为队友的数量。每当一个队友准备好后,调用 CountDownLatch 的 countDown() 方法来减少计数器的值。

  2. 主线程调用 CountDownLatch 的 await() 方法,将会阻塞在这里,直到计数器的值为 0,即所有队友都准备好了。

  3. 以下是一个简单的示例代码:

import java.util.concurrent.CountDownLatch;

public class PlayGame {
    public static void main(String[] args) throws InterruptedException {
        int numOfTeammates = 5; // 队友的数量

        // 创建一个 CountDownLatch 对象,计数器初始值为队友的数量
        CountDownLatch latch = new CountDownLatch(numOfTeammates);

        // 模拟队友准备的过程
        for (int i = 0; i < numOfTeammates; i++) {
            new Thread(() -> {
                try {
                    // 模拟队友准备的时间
                    Thread.sleep((long) (Math.random() * 5000));
                    System.out.println(Thread.currentThread().getName() + " 准备好了");
                    // 队友准备好后,调用 countDown() 方法减少计数器的值
                    latch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }

        System.out.println("等待所有队友准备好...");
        // 主线程调用 await() 方法等待计数器的值为 0
        latch.await();
        System.out.println("所有队友都准备好了,开始游戏!");
    }
}

3. 运行结果:

yunxing

4. 案例分析:

  1. 在上面的示例代码中,首先创建了一个 CountDownLatch 对象,并将计数器初始化为队友的数量。然后,使用多线程模拟队友准备的过程,每个线程准备好后调用 countDown() 方法减少计数器的值。

  2. 最后,主线程调用 await() 方法等待计数器的值为 0,即所有队友都准备好了,然后输出相应的提示信息,表示可以开始游戏。

  3. 注意:CountDownLatch 是一次性的,计数器的值减少到 0 后,无法再次使用。如果需要多次等待,可以考虑使用 CyclicBarrier 类。

四、CountDownLatch的优缺点

1. 优点:

CountDownLatch 是 Java 并发包中的一个工具类,用于控制多个线程的执行顺序。它的主要优点是:

1.1、简单易用:

CountDownLatch 提供了一种简单的机制,可以让一个或多个线程等待其他线程完成某个操作后再继续执行。它的使用方法非常简单,只需在需要等待的线程中调用 await() 方法即可。

1.2、灵活性高:

CountDownLatch 可以用于任意数量的线程等待,而且可以在任意时刻进行倒数计数,不需要事先确定等待线程的数量。

1.3、线程安全:

CountDownLatch 内部使用了多线程并发控制的机制,保证了线程安全性。

2. 缺点:

然而,CountDownLatch 也存在一些缺点:

2.1、只能倒数一次:

CountDownLatch 的计数器只能倒数一次,一旦计数器归零,就无法重置。如果需要重复使用倒数计数功能,就需要重新创建一个新的 CountDownLatch。

2.2、不支持中断:

CountDownLatch 的 await() 方法在等待时无法被中断,只能等倒数计数完成或者等待超时才能退出。

2.3、异常处理困难:

在使用 CountDownLatch 时,如果等待的线程发生异常导致无法完成计数操作,其他线程将一直等待下去,没有异常处理机制。

3. 小结:

总体来说,CountDownLatch 是一种简单有效的线程同步工具,但在某些特定情况下可能不够灵活,需要结合其他并发工具来解决问题。

五、底层原理分析

CountDownLatch是Java多线程中的一个同步工具类,它可以让一个或多个线程等待其他线程完成操作后再继续执行。CountDownLatch类提供了两个重要的方法:await()和countDown()。

1. await()方法:

  • await()方法用于使当前线程等待,直到计数器的值变为0。
  • 在调用await()方法之前,需要通过构造函数指定计数器的初始值。
  • 当一个线程调用await()方法后,如果计数器的值大于0,则该线程会被阻塞,直到计数器的值减到0为止。
  • 当计数器的值为0时,await()方法将立即返回,并且所有等待的线程将被唤醒。

2. countDown()方法:

  • countDown()方法用于将计数器的值减1。
  • 每次调用countDown()方法,计数器的值都会减1。
  • 当计数器的值减到0时,await()方法中阻塞的线程将被唤醒。
  • 下面是CountDownLatch的部分源码分析:
public class CountDownLatch {
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 void countDown() {
	sync.releaseShared(1);
}

private static final class Sync extends AbstractQueuedSynchronizer {
	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;
    	}
	}
}
}
  • 在CountDownLatch的源码中,Sync是一个继承了AbstractQueuedSynchronizer的内部类,它实现了具体的计数逻辑。在Sync中,使用了一个整数来表示计数器的值。在构造函数中,通过setState(count)来初始化计数器的值。tryAcquireShared()方法用于判断计数器是否已经减到0,如果是则返回1,表示可以获取共享资源;如果不是则返回-1,表示无法获取共享资源。tryReleaseShared()方法用于减少计数器的值,并判断是否减到0,如果是则返回true,表示可以唤醒等待的线程;如果不是则返回false。

  • 在await()方法中,调用了sync.acquireSharedInterruptibly(1)方法,该方法会调用Sync中的tryAcquireShared()方法。如果计数器的值不为0,则当前线程会被阻塞,直到计数器的值减到0为止。

  • 在countDown()方法中,调用了sync.releaseShared(1)方法,该方法会调用Sync中的tryReleaseShared()方法。每次调用countDown()方法,计数器的值都会减1。当计数器的值减到0时,tryReleaseShared()方法会返回true,表示可以唤醒等待的线程。

  • 通过上述分析,我们可以看出CountDownLatch的await()方法和countDown()方法是通过对计数器的操作来实现线程的等待和唤醒。当计数器的值减到0时,await()方法中阻塞的线程将被唤醒,继续执行后续的操作。

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

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

相关文章

Unity3D:编辑属性

推荐&#xff1a;将 NSDT场景编辑器 加入你的3D工具链 3D工具集&#xff1a; NSDT简石数字孪生 编辑属性 属性是用于游戏对象组件和资源的设置和选项。 可在 Inspector 窗口中编辑属性。 光源组件显示了各种值和引用属性 属性分为以下主要类别&#xff1a; 引用&#xff1a;…

Scrapy框架之Docker 安装 MongoDB

目录 Docker安装 MongoDB Docker 安装 MongoDB 第一次 MongoDB基础命令 算机存储数据的概念 查看数据库 切换数据库/创建数据库 删除当前数据库 创建集合 查看集合 删除集合 数据的增加 样例 数据的更新 举例 Docker安装 MongoDB Docker Docker 是一个开源的应…

ARM fiq和irq的区别 共享内存 混合联编 6.25

day4 汇编代码初始化系统中&#xff1a; 为什么要保存cpsr&#xff1a;要把其他的状态还原 如&#xff08;N Z&#xff09; user&#xff1a;mov r0,#3cmp r0,#4... //irqmovlt r1,#5irq:mov r0,#10cmp r0,#10moveq r2,#6fiq和irq的区别&#xff1a; fiq和irq的区别&#…

CVPR 2023 | SAN: Side Adapter Network for Open-Vocabulary Semantic Segmentation

CVPR 2023 | SAN: Side Adapter Network for Open-Vocabulary Semantic Segmentation 论文&#xff1a;https://arxiv.org/abs/2302.12242代码&#xff1a;https://github.com/MendelXu/SAN 架构设计 冻结的 CLIP&#xff0c;其位置编码为了适应不同于预训练的输入分辨率&…

贪心算法:解决最优问题的简洁而高效方法

目录 引言&#xff1a; 一. 概念与原理 二. 应用场景 3. 实现方法 4. 优缺点分析 引言&#xff1a; 在计算机科学领域&#xff0c;我们经常面临着需要在一系列选择中找到最优解决方案的问题。贪心算法正是针对这类最优化问题而设计的一种简洁而高效的方法。不同于其他复杂…

Educational Codeforces Round 151 (Rated for Div. 2)(A-B)

打完涨了20分…… 算法选修课就学会了dfs……如果有期末复习的这种劲头&#xff0c;其他算法估计早就学会了&#xff08; A Forbidden Integer 这个还WA了三发…… signed main(){IOS;int n,k,x;bool f1;cf{cin>>n>>k>>x;if(k1)cout<<"NO"…

Quiz 14_2-1: Using Web Services | Python for Everybody 配套练习_解题记录

文章目录 Python for Everybody课程简介Quiz 14_2-1: Using Web Services单选题&#xff08;1-15&#xff09;操作题Autograder : Extracting Data from XML Python for Everybody 课程简介 Python for Everybody 零基础程序设计&#xff08;Python 入门&#xff09; This cou…

Echarts折线图默认不显示数据圆点,鼠标hover时折线图上才显示圆点

option {......tooltip: {trigger: axis,},series: [{symbol: circle,symbolSize: 5,showSymbol: false, // 只有在 tooltip hover 的时候显示symbolitemStyle: { // symbol样式normal: {color: rgb(255, 255, 255),borderColor: rgba(255, 255, 255, 0.2), // symbol边框颜色…

6.20、JAVA 初识序列化与反序列化

初识序列化与反序列化 1 概述 序列化是指将对象的状态信息转换为可以存储或传输形式的过程.在序列化期间,对象将其当前状态写入到临时或持久性存储区.以后可以通过从存储区中读取或者反序列化对象的状态,重新创建该对象. 序列化:利用ObjectOutputStream,把对象的信息,按照固定…

【QT】如何自定义QMessageBox的窗口大小,通过继承QDialog重新实现美观的弹窗

目录 1. QMessageBox原有的弹窗2. 网上第一种方法&#xff1a;通过样式表setStyleSheet实现改变弹窗大小&#xff08;总体不美观&#xff09;3. 网上第二种方法&#xff1a;重写ShowEvent()改变弹窗大小&#xff08;总体也不美观&#xff09;4. 最好的办法&#xff1a;继承QDia…

centos安装k8s

1. 前置 俩台centos服务器,不过多说明,教程基于centos 2. hosts配置 我这样配置&#xff0c;最后没发现那块有联动&#xff0c;望大佬更正 vim /etc/hosts 在末尾添加 192.***** master 192.*** note3. 防火墙 说是要关闭防火墙&#xff0c;我俩台服务器都是基于内网&…

服务器数据库中遭受Devos勒索病毒攻击后解密处理方法,勒索病毒数据恢复

在当今数字化时代&#xff0c;服务器数据库的安全性备受关注。然而&#xff0c;网络安全威胁依然存在&#xff0c;勒索病毒如Devos仍然是一种常见的攻击计算机病毒。最近&#xff0c;收到很多企业的求助&#xff0c;企业的财务系统账套遭到了Devos勒索病毒攻击&#xff0c;导致…

js数组中对象的替换,替换原数组 lodash中一些常用的方法(很实用)

代码 let myArray [{name: John, age: 25},{name: Alice, age: 30},{name: Bob, age: 35} ];// 要替换的对象 let objToReplace {name: Alice, age: 30};// 替换为的对象 let replacementObj {name: Alex, age: 28};// 使用forEach方法 myArray.forEach((obj, index) > …

浙大滨江院Om中心发布首个大规模图文配对遥感数据集,让通用基础模型也能服务遥感领域...

写在前面 2021 年年底&#xff0c;OpenAI 发布了 CLIP&#xff0c;利用带噪的图像-文本配对数据预训练的视觉语言模型&#xff0c;展示了前所未有的图像-文本关联能力&#xff0c;在各种下游任务中取得了惊人的结果。虽然取得了很大的进展&#xff0c;但是这类通用视觉语言基础…

Visual C++中的虚函数和纯虚函数(以策略设计模式为例)

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天来说说Visual C中的虚函数和纯虚函数。该系列帖子全部使用我本人自创的对比学习法。也就是当C学不下去的时候&#xff0c;就用JAVA实现同样的代码&#xff0c;然后再用对比的方法把C学会。 直接说虚函数…

微信小程序 rich-text富文本框 怎么设置里面节点的样式

1、在JS中我们获取数据&#xff0c;在没有类名的情况下 使用正则匹配你想要添加演示的节点 res[1].data[0].f_content为rich-text里面的节点 如图 代码&#xff1a;让获取的节点中的图片的最大宽度为100%,高度为auto this.content res[1].data[0].f_content.replace(/\<…

数据库连接与操作怎么学习? - 易智编译EaseEditing

学习数据库连接和操作是进行数据管理和处理的关键技能之一。下面是一些建议&#xff0c;可以帮助您学习数据库连接和操作&#xff1a; 学习数据库基础知识&#xff1a; 首先&#xff0c;了解数据库的基本概念、术语和原理。掌握关系型数据库和非关系型数据库的特点以及它们之…

Spring Boot中的Elasticsearch自动配置

Spring Boot中的Elasticsearch自动配置 Elasticsearch是一个基于Lucene的分布式全文搜索引擎&#xff0c;它在搜索、分析等方面具有出色的表现。Spring Boot中的Elasticsearch自动配置为我们提供了一种快速集成Elasticsearch的方式&#xff0c;使我们可以在Spring Boot应用程序…

【Unity每日一记】常见的类你都掌握了吗,没有就过来看看吧

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

layui弹出层laydate时间选择一闪而过,无法弹出时间选择

问题&#xff1a;layUI日期框弹不出&#xff0c;一闪而过 laydate.render({elem: #ctime,type: datetime,trigger:click }); 解决方案&#xff1a;关键代码&#xff0c;添加如下代码 trigger:click 实现效果