专栏首页Java 源码分析CountDownLatch 源码分析

CountDownLatch 源码分析

CountDownLatch 源码分析

1. 在阅读源码时做了大量的注释,并且做了一些测试分析源码内的执行流程,由于博客篇幅有限,并且代码阅读起来没有 IDE 方便,所以在 github 上提供JDK1.8 的源码、详细的注释及测试用例。欢迎大家 star、fork ! 2. 由于个人水平有限,对源码的分析理解可能存在偏差或不透彻的地方还请大家在评论区指出,谢谢!

1. 基本介绍

Latch 这个单词的意思就是 “闭锁” ,这也是 jdk1.5 引入的一个并发组件,名字听上去并没有让我们对他的功能并没有什么直观的感受。先粗略解释一下他的功能:我们定义了一个带有数值 n 的 Condition 对象,然后我们调用这个对象上的 await 方法,如果说我们要这个线程继续执行,我们不是调用 signal 而是调用 n 次 countDown 方法。这样等待在这个 Condition 上的所有线程都将被唤醒。    好先来举个例子理解一下上面的文字。

public class CountDownLatchTest {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch1 = new CountDownLatch(1);
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                try {
                    latch1.await();
                    System.out.println(Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        System.out.println("main must done something !");
        Thread.sleep(1000);
        latch1.countDown();
    }
}

先打印了

main must done something !

隔了一秒钟打印了

Thread-0
Thread-1
Thread-2
Thread-3
Thread-4
Thread-5
Thread-8
Thread-7
Thread-6
Thread-9

   很明显,这个组件非常适合我们在一些线程开始之前需要完成 n 件其他的准备工作,每完成一件我们就执行一次 countDown() 也就是计数值减一,唯有在计数值为 0 时我们的线程才会被唤醒继续执行。

2. 结构

   好的,先给一张类图看看他的结构。

   毫无疑问,底层还是采用了 AQS 作为基础并发组件。并且这个类要比我们想像中的简单的多。这个类没有继承和实现任何的接口及父类,他但一个独立的组件,里面就封装了 AQS。

3. 主要方法分析

   其实这这个类里面只有两个有价值的方法,就是 await 和 countDown ,但是这两个方法全都是委托给了 AQS 的 acquireSharedInterruptibly 和 releaseShared 。好了又回到了 AQS ,那么上面的这个 Sync 肯定需要对 tryAcquireShared 和 tryReleaseShared 进行重写。所以说我们只需要分析两个方法。

1. tryAcquireShared

   逻辑超简单,当 state 变量为 0 就返回 1 ,否则返回 -1 也就是失败。很明显我们调用了 await 肯定是当时的 state 值不为 0,自然会阻塞,并尝试唤醒后面的线程。

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

2. tryReleaseShared

countDown 就是让信号量减一操作,所以说他就是进行了减一操作,当为 0 的时候,就会触发唤醒后继节点的操作。

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 归并排序

    归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 首先考虑下如何将将二个有序数列...

    lwen
  • JavaIO

    1.在IO有两种数据传输格式一个是字符流还一个是字节流 但是字符流就会涉及到编码的问题 一开始美国使用的自己的编码表就是ASCII表 中国的字符需要被识别也需要...

    lwen
  • Java多线程JUC

    1. volatile 关键字 多线程访问的时候,一个比较严重的问题就是内存不可见,其实在内存访问的时候每一个线程都有一个自己的缓冲区,每次在做修改的时候都是从...

    lwen
  • [javaSE] 看博客学习多线程的创建方式和优劣比较和PHP多线程

    Runnable是一个接口,定义一个类MyRunnable实现Runnable接口,实现run()方法,

    陶士涵
  • java多线程|创建线程的各种方式

    本网站记录了最全的各种JavaDEMO ,保证下载,复制就是可用的,包括基础的, 集合的, spring的, Mybatis的等等各种,助力你从菜鸟到大牛,记得...

    微笑的小小刀
  • 多线程实现的两种方法及其区别

    1、继承Thread:由于子类重写父类的run(),当调用start()时,直接找子类的run()方法 2、实现Runnable接口:Thread的构造函数中...

    如来
  • 并发基础(三): java线程优先级小试牛刀

    好好学java
  • 某团面试题:JVM 堆内存溢出后,其他线程是否可继续工作?

    最近网上出现一个美团面试题:“一个线程OOM后,其他线程还能运行吗?”。我看网上出现了很多不靠谱的答案。这道题其实很有难度,涉及的知识点有jvm内存分配、作用域...

    乔戈里
  • 某团面试题:JVM 堆内存溢出后,其他线程是否可继续工作?

    最近网上出现一个美团面试题:“一个线程OOM后,其他线程还能运行吗?”。我看网上出现了很多不靠谱的答案。这道题其实很有难度,涉及的知识点有jvm内存分配、作用域...

    芋道源码
  • 美团面试题:JVM堆内存溢出后,其他线程是否可继续工作?

    最近网上出现一个美团面试题:“一个线程OOM后,其他线程还能运行吗?”。我看网上出现了很多不靠谱的答案。这道题其实很有难度,涉及的知识点有jvm内存分配、作用域...

    Spark学习技巧

扫码关注云+社区

领取腾讯云代金券