Java并发系列之五 CountDownLatch源码解析

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Java并发系列之五 CountDownLatch源码解析

CountDownLatch概述



引用一段CountDownLatch类注释


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


CountDownLatch是一个同步辅助类。它可以让一个或者多个线程一直阻塞直到其他线程完成了一些指定的操作。


下面我用一个实战案例来说明下CountDownLatch的使用。开启了5个线程去爬取网络上的数据。当爬取完N条数据时,爬取任务停止,让其他线程去汇总这N条数据。

public class CountDownLatchUsage {
    private final static int TASK_COUNT = 100;
    private volatile int count = 0;
    private CountDownLatch countDownLatch = new CountDownLatch(TASK_COUNT);
    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            while (true) {
                System.out.println("爬取数据中---");
                count++;
                countDownLatch.countDown();
                if (count == TASK_COUNT) break;
            }
        }
    };
    public static void main(String[] args) {
        final CountDownLatchUsage usage = new CountDownLatchUsage();
        ExecutorService service = Executors.newFixedThreadPool(5);
        service.submit(usage.runnable);
        new Thread(){
            @Override
            public void run() {
                super.run();
                try {
                    //这里加一个await()完美的解释了让多个线程阻塞
                    usage.countDownLatch.await();
                    System.out.println("子线程开始做任务");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
        try {
            usage.countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("对数据做汇总 - " + usage.count);
    }
}

…….忽略 97条打印结果


获取到一条数据


获取到一条数据


获取到一条数据


子线程开始做任务


对数据做汇总 - 100


由结果可以看出 主线程和子线程都会等线程池打印完100条数据后打印


源码解析



CountDownLatch内部使用的是 共享锁。当线程调用CountDownLatch的await()。其实线程就是在获取共享锁。CountDownLatch(int count) 构造函数 count参数就是初始化了内部共享锁的Sync的state值。获取到共享锁的条件就是 state == 0。countDown()就是释放共享锁,主要是让state-1。如果执行了count次countDown()。state就等于0。在CountDownLatch上等待的线程将获取共享锁。


1. await()方法

public void await() throws InterruptedException {
        //获取共享锁
        sync.acquireSharedInterruptibly(1);
}
protected int tryAcquireShared(int acquires) {
        //当state==0的时候才能获取到锁
        return (getState() == 0) ? 1 : -1;
}

如果CountDownLatch(int count)构造函数 传入的count>0

只要线程调用了await()方法,那么该线程都会进入AQS的队列中等待。并且阻塞线程。那么只有当CountDownLatch调用了countDown()方法,并且state==0时,线程才能重新唤醒。


2. countDown()方法


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

countDown()方法主要就是用来释放共享锁的。当然这里可能有的读者会有疑问。共享锁不是没有获取到吗,怎么还能释放呢。其实呢这里主要是将state-1了,并且唤醒AQS中等待的线程,自旋获取共享锁.

相关文章
|
12天前
|
设计模式 安全 Java
Java 编程中的设计模式:单例模式的深度解析
【9月更文挑战第22天】在Java的世界里,单例模式就像是一位老练的舞者,轻盈地穿梭在对象创建的舞台上。它确保了一个类仅有一个实例,并提供全局访问点。这不仅仅是代码优雅的体现,更是资源管理的高手。我们将一起探索单例模式的奥秘,从基础实现到高级应用,再到它与现代Java版本的舞蹈,让我们揭开单例模式的面纱,一探究竟。
23 11
|
13天前
|
编解码 开发工具 UED
QT Widgets模块源码解析与实践
【9月更文挑战第20天】Qt Widgets 模块是 Qt 开发中至关重要的部分,提供了丰富的 GUI 组件,如按钮、文本框等,并支持布局管理、事件处理和窗口管理。这些组件基于信号与槽机制,实现灵活交互。通过对源码的解析及实践应用,可深入了解其类结构、布局管理和事件处理机制,掌握创建复杂 UI 界面的方法,提升开发效率和用户体验。
64 12
|
6天前
|
存储 算法 Java
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
本文介绍了 JVM 的内存区域划分、类加载过程及垃圾回收机制。内存区域包括程序计数器、堆、栈和元数据区,每个区域存储不同类型的数据。类加载过程涉及加载、验证、准备、解析和初始化五个步骤。垃圾回收机制主要在堆内存进行,通过可达性分析识别垃圾对象,并采用标记-清除、复制和标记-整理等算法进行回收。此外,还介绍了 CMS 和 G1 等垃圾回收器的特点。
18 0
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
|
12天前
|
缓存 负载均衡 Dubbo
Dubbo技术深度解析及其在Java中的实战应用
Dubbo是一款由阿里巴巴开源的高性能、轻量级的Java分布式服务框架,它致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。
39 6
|
9天前
|
监控 算法 Java
深入解析Java中的垃圾回收机制
本文旨在全面解析Java的垃圾回收机制,探讨其工作原理、常见算法以及在实际开发中的应用。通过对这一重要主题的深入分析,希望帮助读者更好地理解Java虚拟机(JVM)如何管理内存,从而编写出更高效、稳定的Java应用程序。
|
9天前
|
Java 开发者
Java中的异常处理机制深度解析
在Java编程中,异常处理是保证程序稳定性和健壮性的重要手段。本文将深入探讨Java的异常处理机制,包括异常的分类、捕获与处理、自定义异常以及一些最佳实践。通过详细讲解和代码示例,帮助读者更好地理解和应用这一机制,提升代码质量。
12 1
|
10天前
|
分布式计算 Java API
深入解析Java中的Lambda表达式及其应用
本文将深入探讨Java中Lambda表达式的定义、优势及其在实际编程中的应用。通过具体示例,帮助读者更好地理解和使用这一强大的编程工具。
|
2月前
|
监控 网络协议 Java
Tomcat源码解析】整体架构组成及核心组件
Tomcat,原名Catalina,是一款优雅轻盈的Web服务器,自4.x版本起扩展了JSP、EL等功能,超越了单纯的Servlet容器范畴。Servlet是Sun公司为Java编程Web应用制定的规范,Tomcat作为Servlet容器,负责构建Request与Response对象,并执行业务逻辑。
Tomcat源码解析】整体架构组成及核心组件
|
2月前
|
存储 NoSQL Redis
redis 6源码解析之 object
redis 6源码解析之 object
58 6
|
21天前
|
存储 缓存 Java
什么是线程池?从底层源码入手,深度解析线程池的工作原理
本文从底层源码入手,深度解析ThreadPoolExecutor底层源码,包括其核心字段、内部类和重要方法,另外对Executors工具类下的四种自带线程池源码进行解释。 阅读本文后,可以对线程池的工作原理、七大参数、生命周期、拒绝策略等内容拥有更深入的认识。
什么是线程池?从底层源码入手,深度解析线程池的工作原理

热门文章

最新文章

推荐镜像

更多
下一篇
无影云桌面