Java并发 - AQS之CountDownLatch

文章目录

  • 基本使用
  • 源码分析
    • await
    • countDown
    • getCount
  • 可重置的CountDownLatch
  • 总结

CountDownLatch是一个多线程同步工具类,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。主要用来解决一个线程或多个线程等待另外多个线程的场景。

初始化需要指定一个计数器,表示需要等待操作完成的操作数量。由于调用了countDown方法,wait方法会一直阻塞,直到当前计数达到零,之后所有等待的线程都会被释放,任何后续的wait调用都会立即返回。这是一种一次性现象,计数无法重置。如果需要一个重置计数的版本,可以考虑使用CyclicBarrier。

java.util.concurrent.CountDownLatch没有继承和实现其他的类或者接口,同时只暴露了下面几个方法:

  1. void await() throws InterruptedException
  2. boolean await(long timeout, TimeUnit unit) throws InterruptedException
  3. void countDown()
  4. long getCount()

基本使用

CountDownLatch 是 Java 中一个非常有用的同步工具,通常用于等待一组线程完成某些操作。以下是一个简单的使用实例,演示如何使用 CountDownLatch 来等待多个线程完成任务。

import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    public static void main(String[] args) {
        // 创建一个 CountDownLatch,计数为3,参数为需要等待的线程数量
        CountDownLatch latch = new CountDownLatch(3);

        // 创建并启动三个线程
        for (int i = 1; i <= 3; i++) {
            final int threadNumber = i;
            new Thread(() -> {
                try {
                    // 模拟任务执行
                    System.out.println("线程 " + threadNumber + " 正在执行任务...");
                    // 随机休眠
                    Thread.sleep((long) (Math.random() * 1000)); 
                    System.out.println("线程 " + threadNumber + " 完成任务.");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    // 每个线程在完成任务后调用 latch.countDown(),使计数器减1
                    latch.countDown();
                }
            }).start();
        }

        try {
            // 主线程等待,直到计数器减为0
            latch.await();
            System.out.println("所有线程已完成任务,主线程继续执行...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

源码分析

CountDownLatch基于AQS实现,源码很短,大部分在AQS中已经实现了

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;
        }
    }
}

await

await会调用AQS的获取资源的方法,CountDownLatch调用await是会阻塞的,说明获取资源会失败,原因就在于Sync中的tryAcquireShared方法

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

在这里插入图片描述

超时版本

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

在这里插入图片描述

Sync类重写了AQS的tryAcquireShared方法,如果当前计数不为0则返回-1,表示获取资源失败,然后被阻塞,当调用countDown时会将计数器减少1,同时唤醒阻塞的线程判断

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

countDown

通过AQS释放资源,将AQS维护的资源数量减少1

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

getCount

这个方法很简单,就是获取AQS的状态值

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

可重置的CountDownLatch

在RocketMQ源码中有实现,其实就是调用AQS的setState方法重新设置资源数量

private static final class Sync extends AbstractQueuedSynchronizer {
    private final int startCount;

    Sync(int count) {
        setState(count);
    }
	// 重置状态
    protected void reset() {
        setState(startCount);
    }
}

总结

  1. CountDownLatch工作在共享模式,和Semaphore一样
  2. 可中断
  3. 只能使用一次,计数器不可重置

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

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

相关文章

在Linux中搭建WordPress并实现Windows主机远程访问

WordPreWordPress是一个基于PHP开发的开源平台&#xff0c;适用于在支持PHP与MySQL数据库的服务器上搭建个性化博客或网站。同时&#xff0c;它也能够作为功能强大的内容管理系统&#xff08;CMS&#xff09;被广泛应用。 虚拟机&#xff1a;VirtualBox 虚拟机安装&#x1f449…

win10中mysql数据库binlog恢复

win10中mysql数据库binlog恢复 昨天有朋友江湖救急&#xff0c;说测试库里的表不小心删除更新了数据。这里也复习下binlog数据恢复&#xff0c;当然需要一定的条件&#xff1a;首先mysql开启binlog&#xff0c;然后每天需要备份对应的数据库 1 单库单表准备 在恢复数据前&am…

QT开发--文件的读写操作

第十三章 文件的读写操作 Qt提供两种读写纯文本文件的方法&#xff1a; 1、直接使用 QFile 类的IO功能&#xff1b; 2、结合 QFile 和 QTextStream&#xff0c;利用流(Stream)进行操作。 13.1 文件读操作 13.1.1 使用QFile类 Qt封装了QFile类&#xff0c;方便我们对文件进行操…

鸿蒙OS启动流程

启动流程(基于openharmony4.1) 系统上电加载内核后&#xff0c;按照以下流程完成系统各个服务和应用的启动&#xff1a; 内核加载init进程&#xff0c;一般在bootloader启动内核时通过设置内核的cmdline来指定init的位置。init进程启动后&#xff0c;会挂载tmpfs&#xff0c;…

bat脚本banenr

飞出个未来班得 echo off echo .-. echo ( ) echo - echo J L echo ^| ^| echo J L echo ^| ^| echo J L echo …

MySQL-表相关(DDL DML)

文章目录 表的基本操作表的创建表的删除 MySQL中的数据类型整数类型浮点数类型定点数类型日期和时间类型字符串类型charvarchartext 二进制类型 DDL语句查看建表语句修改表名新增字段修改字段(名类型)修改字段(仅类型)删除字段 DML语句insert 增delete 删truncate 语句update 改…

前端学习-CSS的三大特性(十七)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 层叠性 继承性 行高的继承性 优先级 优先级注意点 权重叠加 总结 前言 引入css特性的学习 CSS 有三个非常重要的三个特性:层叠性、继承性、优先级。 层叠…

Android 第5种启动模式:singleInstancePerTask

Android 第5种启动模式&#xff1a;singleInstancePerTask 随着 Android 版本的更新&#xff0c;应用启动模式逐渐丰富。在 Android 12 中&#xff0c;新增了一种启动模式——singleInstancePerTask。它是继 standard、singleTop、singleTask 和 singleInstance 之后的第五种启…

纯css 轮播图片,鼠标移入暂停 移除继续

核心 滚动&#xff1a; animation: 动画名称 20s linear infinite normal;停止&#xff1a; animation: 动画名称 20s linear infinite paused; 完整例子&#xff1a; html: <div class"carousel-wrapper"><div class"carousel"><div cl…

chrome浏览器映射端口

chrome://inspect/#devices 方法2

mysql主从复制及故障修复

一、主MySQL数据库的配置 分别在三台主机&#xff08;chen2/10.110、chen3/10.120、chen4/10.130)中安装mysql数据&#xff0c;其中chen2/10.110作为主MySQL服务器&#xff0c;其余两台作为从MySQL服务器。 1、在主机上部署mysql数据库 详细的请看上一篇&#xff1a;mysql数据…

NewStarCTF2024-Week2-Web-WP

目录 1、复读机 2、你能在一秒内打出八句英文吗 3、遗失的拉链 4、谢谢皮蛋 plus 5、PangBai 过家家&#xff08;2&#xff09; 1、复读机 测了下存在 ssti 没什么说的 fenjing 秒了 2、你能在一秒内打出八句英文吗 每次出来的需要提交的内容都不一样 exp&#xff1a; …

CUDA 全局内存

全局内存在片外。 特点是&#xff1a;容量最大、延迟最大、使用最多 全局内存中的数据是所有线程可见的&#xff0c;Host端可见&#xff0c;且具有与程序相同的生命周期 动态全局内存 主机代码使用CUDA运行时API &#xff1a; cudaMalloc 声明内存空间&#xff1b; cudaFree…

MySQL【知识改变命运】07

MySQL 1&#xff1a;Group by 分组查询1.1&#xff1a;语法&#xff1a;1.2&#xff1a;练习 2&#xff1a;having⼦句3回顾&#xff1a;3&#xff1a;内置函数3.1 :⽇期函数 1&#xff1a;Group by 分组查询 可以根据某列&#xff0c;进行分组查询&#xff0c;比如学校里面的…

基于cloudreve(Docker应用)搭建网盘服务,用于目录的分享和在线预览。

文章目录 I 基于cloudreve(Docker应用)搭建网盘服务安装主要功能设置角色最大容量II 知识扩展:网盘类的文件预览需求背景: iOS可以直接预览PDF等常见格式文件,但是Android浏览器需要先下载文件,才能查看文件内容,因此需要搭建支持目录的分享和在线预览的MinIO文件服务提供…

数据安全存储系统的概念与原理

数据安全存储系统是一种综合性的数据保护方案&#xff0c;旨在确保数据的完整性、保密性和可用性。以下是对数据安全存储系统的详细介绍&#xff1a; 一、概念与原理 数据安全存储系统通过硬件、软件和网络等多个层面的保护措施&#xff0c;防止未经授权的访问、避免数据丢失或…

【MySQL 保姆级教学】表结构的操作(4)

表结构的操作 1. 定义和语法2. 创建表 CREATE2.1 创建表的本质2.2 表的存储引擎2.3 表的字符集和校验规则2.4 创建表实例 3. 查看表结构 DESC3.1 作用3.2 示例 4. 修改表结构 ALTER4.1 添加列 ADD4.2 修改列 MODIFY4.3 删除列 DROP4.4 更改列名 CHANGE 5. 修改表名 RENAME6. 删…

一次性解决vue3引入@jiaminghi/data-view需要手动修改node_modules下文件

修改文件1&#xff1a;node_modules\jiaminghi\data-view\lib\components\decoration6\src\main.vue 修改文件2&#xff1a; node_modules\jiaminghi\data-view\lib\components\decoration3\src\main.vue 修改前&#xff1a; 修改后&#xff1a; 通过打补丁的方式对引用库进行…

【自动驾驶】控制算法(十二)横纵向综合控制 | 从理论到实战全面解析

写在前面&#xff1a; &#x1f31f; 欢迎光临 清流君 的博客小天地&#xff0c;这里是我分享技术与心得的温馨角落。&#x1f4dd; 个人主页&#xff1a;清流君_CSDN博客&#xff0c;期待与您一同探索 移动机器人 领域的无限可能。 &#x1f50d; 本文系 清流君 原创之作&…

Maven与Gradle的区别

Maven与Gradle是两种流行的构建工具&#xff0c;广泛用于Java项目的管理和构建。以下是它们的对比&#xff0c;包括官网、Windows 11配置环境、在IDEA中的相同点和不同点&#xff0c;以及它们各自的优缺点。 官网 Maven官网: https://maven.apache.orgGradle官网: https://gr…