CountDownLatch实现原理
来源:互联网 发布:2017年10月非农数据 编辑:程序博客网 时间:2024/06/05 19:54
CountDownLatch用过很多次了,突然有点好奇,它是如何实现阻塞线程的,猜想是否跟LockSupport有关。今天浏览了一下它的源码,发现其实现是十分简单的,只是简单的继承了AbstractQueuedSynchronizer,便实现了其功能。
实现原理:让需要的暂时阻塞的线程,进入一个死循环里面,得到某个条件后再退出循环,以此实现阻塞当前线程的效果。
下面从构造方法开始,一步步解释实现的原理:
一、构造方法
下面是实现的源码,非常简短,主要是创建了一个Sync对象。
public CountDownLatch(int count) { if (count < 0) throw new IllegalArgumentException("count < 0"); this.sync = new Sync(count); }二、Sync对象
private static final class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 4982264981922014374L; Sync(int count) { setState(count); } int getCount() { return getState(); } protected int tryAcquireShared(int acquires) { return (getState() == 0) ? 1 : -1; } 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; } } }
假设我们是这样创建的:new CountDownLatch(5)。其实也就相当于new Sync(5),相当于setState(5)。setState我们可以暂时理解为设置一个计数器,当前计数器初始值为5。
tryAcquireShared方法其实就是判断一下当前计数器的值,是否为0了,如果为0的话返回1(返回1的时候,就表明当前线程可以继续往下走了,不再停留在调用countDownLatch.await()这个方法的地方)。
tryReleaseShared方法就是利用CAS的方式,对计数器进行减一的操作,而我们实际上每次调用countDownLatch.countDown()方法的时候,最终都会调到这个方法,对计数器进行减一操作,一直减到0为止。
稍微跑偏了一点,我们看看调用countDownLatch.await()的时候,做了些什么。
三、countDownLatch.await()
public void await() throws InterruptedException { sync.acquireSharedInterruptibly(1); }代码很简单,就一句话(注意acquireSharedInterruptibly()方法是抽象类:AbstractQueuedSynchronizer的一个方法,我们上面提到的Sync继承了它),我们跟踪源码,继续往下看:
四、acquireSharedInterruptibly(int arg)
public final void acquireSharedInterruptibly(int arg) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); if (tryAcquireShared(arg) < 0) doAcquireSharedInterruptibly(arg); }
源码也是非常简单的,首先判断了一下,当前线程是否有被中断,如果没有的话,就调用tryAcquireShared(int acquires)方法,判断一下当前线程是否还需要“阻塞”。其实这里调用的tryAcquireShared方法,就是我们上面提到的java.util.concurrent.CountDownLatch.Sync.tryAcquireShared(int)这个方法。
当然,在一开始我们没有调用过countDownLatch.countDown()方法时,这里tryAcquireShared方法肯定是会返回1的,因为会进入到doAcquireSharedInterruptibly方法。
五、doAcquireSharedInterruptibly(int arg)
这个时候,我们应该对于countDownLatch.await()方法是怎么“阻塞”当前线程的,已经非常明白了。其实说白了,就是当你调用了countDownLatch.await()方法后,你当前线程就会进入了一个死循环当中,在这个死循环里面,会不断的进行判断,通过调用tryAcquireShared方法,不断判断我们上面说的那个计数器,看看它的值是否为0了(为0的时候,其实就是我们调用了足够多次数的countDownLatch.countDown()方法的时候),如果是为0的话,tryAcquireShared就会返回1,代码也会进入到图中的红框部分,然后跳出了循环,也就不再“阻塞”当前线程了。需要注意的是,说是在不停的循环,其实也并非在不停的执行for循环里面的内容,因为在后面调用parkAndCheckInterrupt()方法时,在这个方法里面是会调用 LockSupport.park(this);,来禁用当前线程的。
五、关于AbstractQueuedSynchronizer
看到这里,如果各位对AbstractQueuedSynchronizer没有了解过的话,可能代码还是看得有点迷糊,这是一篇我觉得解释得非常好的文章,大家可以看一下:http://ifeve.com/introduce-abstractqueuedsynchronizer/
- CountDownLatch实现原理
- CountDownLatch 和 CyclicBarrier 的运用及实现原理
- java共享锁实现原理及CountDownLatch解析
- 深入分析AbstractQueuedSynchronizer共享锁的实现原理:CountDownLatch
- java共享锁实现原理及CountDownLatch解析
- CountDownLatch的原理
- CountDownLatch 实现多线程协作
- 自己动手简单实现CountDownLatch
- java CountDownLatch原理和示例
- 闭锁CountDownLatch的简单实现
- CountDownLatch & CyclicBarrier源码实现解析
- CountDownLatch实现并发多线程操作
- 基于python实现CountdownLatch机制
- CountDownLatch和CyclicBarrier原理的分析理解
- 多线程之倒计时器CountDownLatch及原理
- CountDownLatch
- CountDownLatch
- CountDownLatch
- 网络通信 Socket 实现TCP
- spring自定义属性编辑器使用dome
- SVN如何解决冲突
- postgresql日志补充
- iT世界的真与实——学习心得
- CountDownLatch实现原理
- 【矩阵幂的和+矩阵快速幂】Power of Matrix UVA
- SSD Tensorflow:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start
- codeforces 862B (二分图 dfs )之 Mahmoud and Ehab and the bipartiteness
- 什么是Hadoop
- extern "C"
- Android开发使用Glide获取图片背景色淡绿色解决办法
- 对React children 的深入理解
- An overview of LabOne programming