JUC-CountDownLatch源码分析

JUC-AQS原理篇
JUC-AQS源码篇
JUC-AQS的Condition之await和signal源码解析

JUC-CountDownLatch基础篇
JUC-CountDownLatch源码分析
JUC-Semaphore基础篇
JUC-Semaphore源码分析
JUC-ReentrantReadWriteLock锁基础篇
JUC-ReentrantReadWriteLock锁源码分析
JUC-ReentrantLock锁基础篇
JUC-ReentrantLock锁源码分析
JUC-CyclicBarrier基础篇
JUC-CyclicBarrier源码分析


建议阅读CountDownLatch源码分析之前, 先阅读JUC-CountDownLatch基础篇,了解一下CountDownLatch用处以及基本用法。

我们知道CountDownLatch是一个同步工具类,表示允许一个或者多个线程来等待其他的线程来完成它们的操作后,才继续执行自己的操作。

1. CountDownLatch类结构图

在这里插入图片描述
CountDownLatch的类结构图很简单,内部就一个继承了AbstractQueuedSynchronizer的静态抽象类Sync。

1.1 CountDownLatch的构造方法

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

此构造方法就是传递一个非负数的count值,来设置计时器的初始值。以后每调用一次countDown方法,计时器的计数值就会减一,知道计时器的计数值为0了,就会唤醒因为调用await方法而阻塞的线程了。

Sync类的构造方法

 Sync(int count) {
            setState(count);
        }

通过这个方法我们知道AQS中的state值,此时在CountDownLatch中就是代表了一个计时器的计数值。

2. await()方法源码

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

直接调用AQS的acquireSharedInterruptibly方法

 public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }

此方法中如果tryAcquireShared方法的返回值小于0,代表计时器的计数值还没有归零,则就调用AQS的doAcquireSharedInterruptibly方法将当前线程加入到同步队列中并且阻塞住(doAcquireSharedInterruptibly源码实现可以参考AQS源码篇中doAcquireShared方法)
而tryAcquireShared方法在AQS中是没有实现的,由CountDownLatch中继承了AQS类的内部类Sync提供了实现。

2.1. doAcquireShared(int arg)方法

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

此方法实现很简单,就是判断state的值是不是0,如果是0的话,就代表计时器的计数值归零了,那么当前线程就不用阻塞了,返回1。如果不是0的话,就代表计时器的计数值还没有归零,那么当前线程需要阻塞了,返回-1。

3. countDown()方法源码

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

直接调用AQS的releaseShared方法

 public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }

如果tryReleaseShared方法的返回值为true,代表已经将计时器的计数值归零了,则就调用AQS的doReleaseShared方法将那些因为调用了await()方法而阻塞住的线程唤醒,告诉它们,计时器的计数值归零了。这里就体现出来了CountDownLatch的用法,一个线程需要等待其他线程都操作完,才能接着干自己的事情。这里tryReleaseShared方法返回true,就表示了其他线程都操作完,这个线程可以接着干自己的事情了(doReleaseShared方法的源码可以参考AQS源码篇
而tryReleaseShared方法在AQS中是没有实现的,由CountDownLatch中继承了AQS类的内部类Sync提供了实现。

3.1 tryReleaseShared方法源码

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

此方法大致流程就是:

  1. 开始一个死循环
  2. 获取计时器的计数值,赋值给c变量。
  3. 如果c为0,代表计时器的计数值早就归零了,那么就不需要当前线程多此一举,去唤醒了,直接返回false。
  4. 如果c不为0,就将c减一赋值给nextc变量。并通过CAS操作将计时器的计数值更新为nextc变量值
  5. CAS操作成功了,就将nextc变量与0相比较。
  6. 如果nextc变量等于0,就说明了计时器的计数值已经归零了,返回true,唤醒因调用await返回阻塞的线程。如果不等于0,就说明计时器的计数值还没有归零,直接返回false。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值