转载

Semaphore、CountDownLatch 的实现原理浅析

搞懂这篇文章的前提是对 Lock 的几种实现以及 AQS 的源码原理有一定了解,如果不了解的话可以看下 Lock 中的 AQS、独占锁、重入锁、读锁、写锁、Condition 源码原理分析 ,本文源码未贴出来自己去翻下然后跟着图的调用逻辑走就能理清了

Semaphore

Semaphore(信号量)它通过 new Semaphore(permits) 来进行创建,permits 表示同一时间可以执行多少个线程。

使用 acquire 来获得许可,通过 release 来释放许可。在同一时间只允许 permits 个线程同时运行。

Semaphore、CountDownLatch 的实现原理浅析
Semaphore、CountDownLatch 的实现原理浅析

可以看到输出结果,当线程数量达到上限的时候,其它线程无法执行,释放了一个线程后归还一个信号量,那么下一个线程才能执行。

它的实现原理如下

Semaphore、CountDownLatch 的实现原理浅析
new Semaphore(5);
Semaphore、CountDownLatch 的实现原理浅析

CountDownLatch

CountDownLatch 内部维护了一个计数器,当计数器不为 0 的时候调用其 await() 可以进行阻塞,每次使用 countDown() 计数器值 - 1,当计数器值为 0 的时候,所有阻塞的线程从 await() 返回

利用这个特性我们可以用来合并多个线程最终的结果,或者以此来模拟并发请求调用等等,如下并发请求代码

此处的“锁”的成功与否表现其实就是 CountDownLatch 的一个同步值的变化

Semaphore、CountDownLatch 的实现原理浅析
Semaphore、CountDownLatch 的实现原理浅析

我们来分析下 CountDownLatch 是如何做到的以下两张图分别展示了在 countDown() 和 await() 的原理,源码跟着看就行了就不贴出来了

Semaphore、CountDownLatch 的实现原理浅析
Semaphore、CountDownLatch 的实现原理浅析
  1. countDown 的时候每次调用都会对 state 减 1 也就是我们 new CountDownLatch(10); 的这个计数器的数字减 1,如果为 0 的话说明该唤醒同步队列中的等待结点了,如果大于 0 的话这直接返回。

此时唤醒同步队列中的等待结点后,await() 中挂起的线程将被唤醒,然后再次将下一个结点设置为头结点,唤醒下一个结点如此往复,最终所有的线程将被唤醒

  1. 此时后面调用了 await 方法它会去获取同步值发现为 0 的话成功返回,如果小于 0 的话,再次判断是否是头结点,如果是的话再次尝试获取同步值,如果发现 state 为 0 的话则将当前节点断开,设置同步队列中的下一个结点为头结点,调用释放锁逻辑。如果 state 不为 0 或者发现不是头结点就直接将线程挂起
原文  https://juejin.im/post/5e0420a7f265da33b0718c67
正文到此结束
Loading...