Java 之 CountDownLatch 原理篇

目录

  • 引言
  • 测试程序
  • await 阻塞
  • countDown
  • 总结

引言

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 会使线程阻塞,那它又是如何实现阻塞的呢?
Java 之 CountDownLatch 原理篇_第1张图片
通过跟踪源码 countDownLatch.await(); 最终会调到 AbstractQueuedSynchronizer 类的 doAcquireSharedInterruptibly 方法;然后看到 parkAndCheckInterrupt() 这个方法的调用
Java 之 CountDownLatch 原理篇_第2张图片
parkAndCheckInterrupt() 方法中通过 LockSupport.park(this) 阻塞当前线程,调用park后当前线程状态会从RUNNABLE 变为 WAITING;

countDown

既然 CountDownLatch.await() 会阻塞,那又是如何进行唤醒呢?
Java 之 CountDownLatch 原理篇_第3张图片
如图可看出 CountDownLatch 并没有提供直接唤醒的方法;
既然 CountDownLatch 维护的是一个计数器,那应该是计数器减为0时进行唤醒;
Java 之 CountDownLatch 原理篇_第4张图片
Java 之 CountDownLatch 原理篇_第5张图片
Java 之 CountDownLatch 原理篇_第6张图片
Java 之 CountDownLatch 原理篇_第7张图片
通过跟踪源码 countDown()方法,最终会调 tryReleaseShared() 方法对计数器减1,当计数器减到0时,开始唤醒阻塞的主线程,最后调 LockSupport.unpark(s.thread); 进行唤醒。

总结

CountDownLatch 内部维护了一个 Sync 内部类来实现计数,Sync 实现了 AbstractQueuedSynchronizer 类,ReentrantLock 也是通过内部使用AbstractQueuedSynchronizer 来实现的锁机制;AbstractQueuedSynchronizer 内部使用了LockSupport.park() 和 LockSupport.unpark() 来实现线程的阻塞和唤醒;
Java 之 CountDownLatch 原理篇_第8张图片
CountDownLatch 实现原理:
CountDownLatch → AbstractQueuedSynchronizer → LockSupport

你可能感兴趣的:(随手记,JavaSE,java,开发语言,后端)