Java 之 CountDownLatch 原理篇

引言

CountDownLatch 就像游戏中的打BOOS,打BOOS之前有几道关卡,必须通过这几道关卡才能见到BOOS;
CountDownLatch 可以通过设置一个计数器,当计数器到0之前都会阻塞在 await 前面,通常是在多线程时,在子线程执行完后调用countDown进行倒数,待所有子线程执行完,计数器倒为0时再执行主线程 await 后面的逻辑;

测试程序

import java.util.concurrent.CountDownLatch;

public class CountDownLatchTest {

    public static void main(String[] args) throws Exception {
        CountDownLatch countDownLatch = new CountDownLatch(1);
        System.out.println(countDownLatch.getCount());

        new Thread(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " " + countDownLatch.getCount());
            countDownLatch.countDown();
        }, "t1").start();

        System.out.println(Thread.currentThread().getName() + " " + countDownLatch.getCount());

        countDownLatch.await();
        System.out.println(Thread.currentThread().getName() + " " + countDownLatch.getCount());
    }
}

await 阻塞

既然 await 会使线程阻塞,那它又是如何实现阻塞的呢?
在这里插入图片描述
通过跟踪源码 countDownLatch.await(); 最终会调到 AbstractQueuedSynchronizer 类的 doAcquireSharedInterruptibly 方法;然后看到 parkAndCheckInterrupt() 这个方法的调用
在这里插入图片描述
parkAndCheckInterrupt() 方法中通过 LockSupport.park(this) 阻塞当前线程,调用park后当前线程状态会从RUNNABLE 变为 WAITING;

countDown

既然 CountDownLatch.await() 会阻塞,那又是如何进行唤醒呢?
在这里插入图片描述
如图可看出 CountDownLatch 并没有提供直接唤醒的方法;
既然 CountDownLatch 维护的是一个计数器,那应该是计数器减为0时进行唤醒;
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
通过跟踪源码 countDown()方法,最终会调 tryReleaseShared() 方法对计数器减1,当计数器减到0时,开始唤醒阻塞的主线程,最后调 LockSupport.unpark(s.thread); 进行唤醒。

总结

CountDownLatch 内部维护了一个 Sync 内部类来实现计数,Sync 实现了 AbstractQueuedSynchronizer 类,ReentrantLock 也是通过内部使用AbstractQueuedSynchronizer 来实现的锁机制;AbstractQueuedSynchronizer 内部使用了LockSupport.park() 和 LockSupport.unpark() 来实现线程的阻塞和唤醒;
在这里插入图片描述
CountDownLatch 实现原理:
CountDownLatch → AbstractQueuedSynchronizer → LockSupport

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值