1:CountdownLatch 基本知识
1:CountDownLatch 允许一个或多个线程阻塞,等待其他线程完成操作。
2:有一个计数器,表示需要等待的事件数量
3:进入终止状态后,不可重置,不能重复使用。
2:构造方法
传入 int 整数,作为初始化计数器的值
public CountDownLatch(int count) {
// int 数值 < 0 ,抛出异常
if (count < 0) throw new IllegalArgumentException("count < 0");
// 进入 Sync(count) 方法
this.sync = new Sync(count);
}
进入 Sync(count) 方法
Sync(int count) {
// 把传入的 int 数值作为 AQS 的 state 的初始值
setState(count);
}
3:阻塞等待方法
调用 await() 方法
public void await() throws InterruptedException {
// 进入 acquireSharedInterruptibly(1) 方法
sync.acquireSharedInterruptibly(1);
}
进入 acquireSharedInterruptibly(1) 方法
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
// 检查中断
if (Thread.interrupted())
throw new InterruptedException();
// 进入 tryAcquireShared(1) 方法
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
进入 tryAcquireShared(1) 方法
protected int tryAcquireShared(int acquires) {
// 判断 state 的数目是否等于 0 ,是返回 1,否则返回 -1.我们假设返回 -1
return (getState() == 0) ? 1 : -1;
}
回到 acquireSharedInterruptibly(1) 方法
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// tryAcquireShared(1) 返回 -1 ,< 0
if (tryAcquireShared(arg) < 0)
// 进入 doAcquireSharedInterruptibly(1) 方法
doAcquireSharedInterruptibly(arg);
}
进入 doAcquireSharedInterruptibly(1) 方法
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
// 根据当前线程创建一个节点,作为等待队列的尾节点
// 如果是第一个进入等待队列的,会创建一个亚元节点,作为头节点
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
// 再次判断 state 的值 是否等于0,返回 -1
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
// shouldParkAfterFailedAcquire() :将当前节点的前一个节点的 waitStatus 从 0 变成 -1
// parkAndCheckInterrupt():使当前线程进入阻塞状态。当被唤醒后,继续进入 循环
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
3:countDown 方法
调用 countDown() 方法,使 state 的值 -1
public void countDown() {
// 进入 releaseShared(1) 方法
sync.releaseShared(1);
}
进入 releaseShared(1) 方法
public final boolean releaseShared(int arg) {
// 进入 tryReleaseShared(1) 方法
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
进入 tryReleaseShared(1) 方法
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
// 获取 state 的值
int c = getState();
// state 等于0 ,返回 false
if (c == 0)
return false;
// state >0 ,减1,并通过 cas 去更新 state 的值 ,再去判断 state 的值是否等于0 ,我们假设返回 true
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
回到 releaseShared(1) 方法
public final boolean releaseShared(int arg) {
// tryReleaseShared(1) 返回 true
if (tryReleaseShared(arg)) {
// 进入 doReleaseShared(1) 方法
doReleaseShared();
return true;
}
return false;
}
进入 doReleaseShared(1) 方法
private void doReleaseShared() {
for (;;) {
Node h = head;
// 等待队列中有至少两个节点
if (h != null && h != tail) {
// 判断头节点的 waitStatus 是否等于 -1
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
// cas 将头节点的 waitStatus 修改成 0 成功
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue;
// 进入 unparkSuccessor(h) 方法 ,将 头节点之后的第二个节点解除阻塞。
// ps:解除阻塞的线程在 doAcquireSharedInterruptibly(1) 方法里的 for 循环运行
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
进入 unparkSuccessor(h) 方法
private void unparkSuccessor(Node node) {
// 拿到头节点的 waitStatus 值 0
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
// 取到头节点的后一个节点 s
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
// 让头节点后的第二个节点解除阻塞状态
if (s != null)
LockSupport.unpark(s.thread);
}