我的原则:先会用再说,内部慢慢来。
学以致用,根据场景学源码
一、概念
- CountDownLatch 理解为:手动倒计时。(输入一个整数,然后每次-1,直到state = 0,退出)
也叫做闭锁,在完成某些运算是,只有其他所有线程的运算全部完成,当前运算才继续执行。
可以用于计算数量,平均值,等待线程退出等等等等。
二、主要方法
- CountDownLatch#countDown 递减1
- CountDownLatch#await() 共享锁阻塞等待 state = 0
三、源码分析
为了便于理解,建议先读一下我的另一篇文章,介绍AQS 【线程】ReentrantLock 源码剖析 (八)
3.1 整体架构
package java.util.concurrent;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
public class CountDownLatch {
// 继承 AQS 的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) { //尝试进行加锁 ,getState() == 0表示当前空闲,没人占据锁,我可以拿到
return (getState() == 0) ? 1 : -1;
}
protected boolean tryReleaseShared(int releases) { //尝试释放锁,这个 releases参数没鸟用
// Decrement count; signal when transition to zero
for (;;) {
int c = getState(); //获取状态
if (c == 0) //是0的话,说明没有锁了,那么就释放失败,返回 false
return false;
int nextc = c-1; //每次释放 1
if (compareAndSetState(c, nextc)) //CAS 设置状态,不成功就for自旋,必须设置成功为止
return nextc == 0;
}
}
}
private final Sync sync;
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
public void await() throws InterruptedException { sync.acquireSharedInterruptibly(1); } //等待条件满足被唤醒
public boolean await(long timeout, TimeUnit unit) //等待条件满足被唤醒 (条件加了个超市)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
public void countDown() { sync.releaseShared(1); } // -1操作,拿掉一个锁
public long getCount() { return sync.getCount(); } // 获取锁数量
public String toString() { return super.toString() + "[Count = " + sync.getCount() + "]"; }
}
3.2 CountDownLatch 初始化
final CountDownLatch latch = new CountDownLatch(2);
- 看下构造方法 CountDownLatch(int count)
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
Sync(int count) {
setState(count);
}
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable {
...
private volatile int state; // 当前持有锁的数量,0表示没人持有锁
protected final void setState(int newState) {
state = newState;
}
...
}
初始化的目的就是:套N个锁上去,然后一个个拿掉。
3.3 await 剖析
java.util.concurrent.CountDownLatch#sync
- await 方法
public void CountDownLatch#await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
- acquireSharedInterruptibly 方法
public final void AbstractQueuedSynchronizer#acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException(); // 被打断就直接抛异常了
if (tryAcquireShared(arg) < 0) // -1 没拿到锁,1 拿到了锁。
doAcquireSharedInterruptibly(arg); // -1没拿到锁才进入这个方法
}
- tryAcquireShared 方法
protected int Sync#tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1; // -1 没拿到锁,1 拿到了锁。
}