CountDownLatch 源码分析

1. 类介绍

一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达零之前,await 方法会一直受阻塞。之后,会释放所有等待的线程,await 的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。

2. 使用场景

在一些应用场合中,需要等待某个条件达到要求后才能做后面的事情。 CountDownLatch最重要的方法是countDown()和await()两个方法,countDown主要是倒数一次,await是等待倒数到0,如果没有到达0,就只有阻塞等待了。 例如: A 和 B 相约一起吃饭,等A和B都到指定顶点后才能开始吃饭,下面用代码模拟实现。

示例

public class CountDownLatchTest {
    static CountDownLatch c = new CountDownLatch(2);
    
    public static void main(String[] args) {
        new Thread(new Runnable() {
            public void run() {
                System.out.println("A 我来了");
                c.countDown();
            }
        }).start();

        new Thread(new Runnable() {
            public void run() {
                System.out.println("B 我来了");
                c.countDown();
            }
        }).start();

        new Thread(new Runnable() {
            public void run() {
                try {
                    c.await();
                    System.out.println("开始吃饭...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }
}

源码分析:

需要提前了解:AbstractQueuedSynchronizer 源码分析

AQS提供了两种模式:独占模式&共享模式。CountDownLatch就是一个使用共享模式的自定义同步器实现的共享锁。

CountDownLatch 代码不多,主要是通过内部类继承AQS来实现其功能的,下面我们一步一步来分析下源码:

Sync 内部类

private static final class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = 4982264981922014374L;

    //构造Sync对象是初始化AQS中state的数量(共享锁的个数)
    Sync(int count) {
        setState(count);
    }

    //获取当前state的数量(共享锁个数)
    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;
        }
    }
}

AbstractQueuedSynchronizer 类采用模版模式进行扩展实现其相应的功能。子类只需要实现 如下5个方法就能实现其不同功能的锁。

Paste_Image.png

而CountDownLatch 的内部类Sync使用的是共享锁所以只实现了tryAcquireShared和tryReleaseShared方法。

CountDownLatch的构造方法

public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    this.sync = new Sync(count);
}

创建CountDownLatch对象时,需要传入一个int的计数器。

await 方法

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

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

await方法调用AQS的获得锁的方法,只有AQS的state状态为0时才能获得锁,如果state不为0,则需要在AQS的等待队列中阻塞等待。

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

countDown方法则调用AQS的releaseShared方法,释放共享锁,也就是每次将state状态每次减一,直到减到0,则唤醒队列中的所有节点(线程)。

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

获取计数器当前值。


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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java 技术分享

JavaWeb 之文件的上传下载

62050
来自专栏企鹅FM

形形色色的锁2

synchronized关键字提供了一套非常完整的java内置锁实现,简单易用通过块语句控制锁的范围,而且性能不低,隐藏了偏向锁,轻量、重量锁等复杂的概念,对程...

30550
来自专栏博客园迁移

CountDownLatch和CyclicBarrier模拟同时并发请求

  有时候要测试一下某个功能的并发能力,又不要想借助于其他测试工具,索性就自己写简单的demo模拟一个并发请求就最方便了。如果熟悉jemter的测试某接口的并发...

24610
来自专栏Script Boy (CN-SIMO)

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1

场景:eclipse中编写java中用到数组 问题:       程序不报错但是运行过程中 终止,显示字样 “ Exception in thread "...

21400
来自专栏about云

hive文件存储格式:SequenceFile系统总结

问题导读 1.什么是SequenceFile? 2.如何 通过 源码实现SequenceFile压缩? 3.SequenceFile格式压缩有什么优点和缺点?...

47280
来自专栏JavaQ

高并发编程-ReentrantLock非公平锁深入解析

ReentrantLock是一个可重入的互斥锁,它不但具有synchronized实现的同步方法和同步代码块的基本行为和语义,而且具备很强的扩展性。Reentr...

12940
来自专栏Android相关

Android中的Proguard介绍

ProGuard是一个Java Class文件的Shrinker,optimizer,obfuscator以及Preverifier。

16330
来自专栏格子的个人博客

Java源码阅读之ReentrantLock - lock和unLock方法

如果需要使用或者了解ReentrantLock,证明已经步入并发编程领域了,这里理论基础不多提,需要的自行查阅资料。

10520
来自专栏微信公众号:Java团长

synchronized与Lock的区别与使用详解

昨天在学习别人分享的面试经验时,看到Lock的使用。想起自己在上次面试也遇到了synchronized与Lock的区别与使用。于是,我整理了两者的区别和使用情况...

17020
来自专栏Android相关

Java多线程---ReentrantLock解析

ReentrantLock中有两种Sync,一种是NonfairSync另一种是FairSync。它两同时继承Sync类。可以在创建ReentrantLock的...

9410

扫码关注云+社区

领取腾讯云代金券