0
点赞
收藏
分享

微信扫一扫

Java 之 CountDownLatch 原理篇

四月Ren间 2022-02-10 阅读 65

目录

引言

测试程序

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 条评论