Java并发编程之CountDownLatch原理详解

 更新时间:2023年12月11日 08:48:16   作者:程光CS  
这篇文章主要介绍了Java并发编程之CountDownLatch原理详解,CountDownLatch类中使用了一个继承自AQS的共享锁Sync对象,构造CountDownLatch对象时会将传入的线程数值设为AQS的state值,需要的朋友可以参考下

一、CountDownLatch介绍

在日常开发中经常会遇到需要在主线程中开启多个线程去并行执行任务,并且主线程需要等待所有子线程执行完毕后再进行汇总的场景。

在 CountDownLatch 出现之前一般都使用线程的join()方法来实现这一点,但是 join 方法不够灵活,不能够满足不同场景的需要,所以JDK开发组提供了 CountDownLatch 这个类,使用CountDownLatch 会更优雅。

并且CountDownLatch 可以在子线程的任何位置让 await 方法返回而不一定必须线程结束,这比join更加灵活。使用 CountDownLatch 的代码如下:

public static void main(String[] args) throws InterruptedException {
    //内部sync同步器的state值设为3
    CountDownLatch countDownLatch = new CountDownLatch(3);

    for (int i = 1;i <= 3;i++) {
        new Thread(() -> {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("目标代码块运行完毕");
                //每调用一次countDown()内部调用releaseShared(1)都会使state值减一
                countDownLatch.countDown();
            }
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程结束");
        }).start();
    }
    System.out.println("所有线程已启动");
    //主线程调用await()方法后就会进入阻塞,直到所有线程调用了countDown()使state值被减为0,或者主线程被中断,才会从阻塞返回
    countDownLatch.await();
    System.out.println("所有线程目标代码块已运行完毕");
}

二、CountDownLatch原理

CountDownLatch类中使用了一个继承自AQS的共享锁Sync对象,构造CountDownLatch对象时会将传入的线程数值设为AQS的state值

当一个线程结束运行调用countDown()方法时,内部调用releaseShared(1)时调用Sync中重写的钩子方法tryReleaseShared()都会使state值减一,当被state被减为0后tryReleaseShared才会返回true,继而调用doReleaseShared唤醒同步队列中被阻塞的线程

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

主线程调用await()方法后就会进入阻塞,其内部调用的acquireSharedInterruptibly方法,只有当钩子方法tryAcquireShared返回值>=0时才能拿到锁,而Sync中重写的tryAcquireShared只有当state为0才会返回1,否则返回-1,因此只有到最后一个线程调用了countDown()使state值被减为0继而唤醒同步队列中阻塞的主线程,或者主线程被中断,才会从阻塞返回。

到此这篇关于Java并发编程之CountDownLatch原理详解的文章就介绍到这了,更多相关CountDownLatch原理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java编程基础元素-运算符

    Java编程基础元素-运算符

    这篇文章主要介绍了Java编程基础元素-运算符,运算符就是在用变量或常量进行运算时,经常需要用到的运算符,Java 提供了丰富的运算符,可分为算术运算符、关系运算符、逻辑运算符和位运算符,下面来看具体的内容介绍吧
    2022-01-01
  • 浅谈在JAVA项目中LOG4J的使用

    浅谈在JAVA项目中LOG4J的使用

    下面小编就为大家带来一篇浅谈在JAVA项目中LOG4J的使用。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • Java中的NoClassDefFoundError报错含义解析

    Java中的NoClassDefFoundError报错含义解析

    这篇文章主要为大家介绍了Java中的NoClassDefFoundError含义详解,有需要的朋友可以借鉴参考下,希望能够有所帮助
    2023-11-11
  • SpringBoot disruptor高性能队列使用

    SpringBoot disruptor高性能队列使用

    这篇文章主要介绍了SpringBoot disruptor高性能队列使用,Disruptor是英国外汇交易公司LMAX开发的一个高性能队列,研发的初衷是解决内存队列的延迟问题
    2023-02-02
  • Java模拟服务器解析web数据

    Java模拟服务器解析web数据

    本篇文章主要给大家详细分享了搭建JavaWeb服务器的详细步骤以及用到的代码,对此有需要的朋友可以跟着学习下,希望能给你带来帮助
    2021-07-07
  • springboot中如何使用自定义两级缓存

    springboot中如何使用自定义两级缓存

    本话题主要就是讨论如何在springboot的基础上,无缝集成ehcache和redis作为一二级缓存,并且实现缓存同步。
    2021-05-05
  • SpringBoot Controller中的常用注解

    SpringBoot Controller中的常用注解

    这篇文章主要介绍了SpringBoot Controller中的常用注解,文章围绕主题展开详细的内容介绍,具有有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09
  • SpringBoot集成Mybatis的实现步骤

    SpringBoot集成Mybatis的实现步骤

    这篇文章主要介绍了SpringBoot集成Mybatis的实现步骤,本文通过SpringBoot +MyBatis 实现对数据库学生表的查询操作,需要的朋友可以参考下
    2020-12-12
  • 使用RocketMQTemplate发送带tags的消息

    使用RocketMQTemplate发送带tags的消息

    这篇文章主要介绍了使用RocketMQTemplate发送带tags的消息,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • java高并发的并发级别详解

    java高并发的并发级别详解

    这篇文章主要介绍了java高并发的并发级别,内容十分丰富,在这里分享给大家,需要的朋友可以参考,希望能够给你带来帮助
    2021-10-10

最新评论