JUC-CountDownLatch基础篇
JUC-CountDownLatch源码分析
JUC-Semaphore基础篇
JUC-Semaphore源码分析
JUC-ReentrantReadWriteLock锁基础篇
JUC-ReentrantReadWriteLock锁源码分析
JUC-ReentrantLock锁基础篇
JUC-ReentrantLock锁源码分析
JUC-CyclicBarrier基础篇
JUC-CyclicBarrier源码分析
文章目录
-
- CountDownLatch类结构图
-
- 1.1 CountDownLatch的构造方法
-
- await()方法源码
-
- 2.1. doAcquireShared(int arg)方法
-
- countDown()方法源码
-
- 3.1 tryReleaseShared方法源码
建议阅读CountDownLatch源码分析之前, 先阅读JUC-CountDownLatch基础篇,了解一下CountDownLatch用处以及基本用法。
我们知道CountDownLatch是一个同步工具类,表示允许一个或者多个线程来等待其他的线程来完成它们的操作后,才继续执行自己的操作。
1. CountDownLatch类结构图
CountDownLatch的类结构图很简单,内部就一个继承了AbstractQueuedSynchronizer的静态抽象类Sync。
1.1 CountDownLatch的构造方法
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
此构造方法就是传递一个非负数的count值,来设置计时器的初始值。以后每调用一次countDown方法,计时器的计数值就会减一,知道计时器的计数值为0了,就会唤醒因为调用await方法而阻塞的线程了。
Sync类的构造方法
Sync(int count) {
setState(count);
}
通过这个方法我们知道AQS中的state值,此时在CountDownLatch中就是代表了一个计时器的计数值。
2. await()方法源码
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
直接调用AQS的acquireSharedInterruptibly方法
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
此方法中如果tryAcquireShared方法的返回值小于0,代表计时器的计数值还没有归零,则就调用AQS的doAcquireSharedInterruptibly方法将当前线程加入到同步队列中并且阻塞住(doAcquireSharedInterruptibly源码实现可以参考AQS源码篇中doAcquireShared方法)
而tryAcquireShared方法在AQS中是没有实现的,由CountDownLatch中继承了AQS类的内部类Sync提供了实现。
2.1. doAcquireShared(int arg)方法
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
此方法实现很简单,就是判断state的值是不是0,如果是0的话,就代表计时器的计数值归零了,那么当前线程就不用阻塞了,返回1。如果不是0的话,就代表计时器的计数值还没有归零,那么当前线程需要阻塞了,返回-1。
3. countDown()方法源码
public void countDown() {
sync.releaseShared(1);
}
直接调用AQS的releaseShared方法
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
如果tryReleaseShared方法的返回值为true,代表已经将计时器的计数值归零了,则就调用AQS的doReleaseShared方法将那些因为调用了await()方法而阻塞住的线程唤醒,告诉它们,计时器的计数值归零了。这里就体现出来了CountDownLatch的用法,一个线程需要等待其他线程都操作完,才能接着干自己的事情。这里tryReleaseShared方法返回true,就表示了其他线程都操作完,这个线程可以接着干自己的事情了(doReleaseShared方法的源码可以参考AQS源码篇)
而tryReleaseShared方法在AQS中是没有实现的,由CountDownLatch中继承了AQS类的内部类Sync提供了实现。
3.1 tryReleaseShared方法源码
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;
}
}
此方法大致流程就是:
1、 开始一个死循环;
2、 获取计时器的计数值,赋值给c变量;
3、 如果c为0,代表计时器的计数值早就归零了,那么就不需要当前线程多此一举,去唤醒了,直接返回false;
4、 如果c不为0,就将c减一赋值给nextc变量并通过CAS操作将计时器的计数值更新为nextc变量值;
5、 CAS操作成功了,就将nextc变量与0相比较;
6、 如果nextc变量等于0,就说明了计时器的计数值已经归零了,返回true,唤醒因调用await返回阻塞的线程如果不等于0,就说明计时器的计数值还没有归零,直接返回false;