基于AQS实现,有关AQS的原理参考juejin.cn/post/748158... ,本文涉及AQS的方法不再重复分析。
构造方法
arduino
public CountDownLatch(int count) {
//参数值校验
if (count < 0) throw new IllegalArgumentException("count < 0");
//创建Sync类,继承AQS
this.sync = new Sync(count);
}
scss
Sync(int count) {
//设置state值
setState(count);
}
await()
csharp
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
java
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
//中断状态,抛出中断异常
if (Thread.interrupted())
throw new InterruptedException();
// state等于0说明所有的线程都已经countDown了
if (tryAcquireShared(arg) < 0)
//加入同步队列并阻塞
doAcquireSharedInterruptibly(arg);
}
arduino
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
java
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
//构建共享模式节点添加到同步队列
//这里同步队列里就只是一个哨兵节点和一个执行await()线程节点
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
//前驱节点
final Node p = node.predecessor();
//是头节点
if (p == head) {
//看state是否等于0
int r = tryAcquireShared(arg);
if (r >= 0) {
//设置头节点并传播后续节点
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
if (
//尝试失败是否需要阻塞
shouldParkAfterFailedAcquire(p, node) &&
//阻塞,中断了的话抛出异常
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
//失败清楚节点
cancelAcquire(node);
}
}
await()逻辑总结:
- 先尝试查看state是不是0,是0说明所有的线程都已经countDown了;
- 不是0,说明还有线程没有走完业务逻辑执行countDown操作,把执行await()方法的线程加入到同步队列;
- 前驱节点是头节点的话先尝试在看state是否是0,不是的话阻塞线程,等countDown后为0唤醒
countDown()
csharp
public void countDown() {
sync.releaseShared(1);
}
arduino
public final boolean releaseShared(int arg) {
//判断state是否是正常countDown操作减为0
if (tryReleaseShared(arg)) {
//唤醒同步队列节点,也就是执行await()的线程
doReleaseShared();
return true;
}
return false;
}
ini
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
//状态减1
int nextc = c-1;
//CAS设置
if (compareAndSetState(c, nextc))
//为0成功
return nextc == 0;
}
}
countDown()逻辑总结:
- 循环减1state直到为0,然后唤醒执行await()的线程