假如有4个线程ABCD,其中A、B需要等待C、D执行到某个点后再执行,那么就可以使用CountDownLatch实现。
主要方法
初始化方法,会初始化Sync的内部变量state,
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
state代表资源数
Sync(int count) {
setState(count);
}
protected final void setState(int newState) {
state = newState;
}
- countDown
当countdownlatch的countdown方法被执行state次后,执行await方法的线程会被唤醒继续执行。
public void countDown() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
判断state值是否等于0,等于0会调用doReleaseShared方法,唤醒因await方法阻塞的线程
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
释放资源会循环调用cas方法将state的值减1,如果最后state==0,返回true,说明countdown方法执行完了,state=0
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;
}
}
private void doReleaseShared() {
for (;;) {
进入循环后,取得当前队列头节点线程,
Node h = head;
头节点存在并且队列中存在两个节点以上,说明至少一个线程节点进入了队列
if (h != null && h != tail) {
获取线程状态
int ws = h.waitStatus;
如果是SIGNAL状态,就尝试设置线程状态为0,并唤醒后继节点线程
if (ws == Node.SIGNAL) {
if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!h.compareAndSetWaitStatus(0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
唤醒后继节点线程方法
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
node.compareAndSetWaitStatus(ws, 0);
获取后继节点
Node s = node.next;
后继节点有效则直接唤醒,无效则从队列尾部开始向前找到一个靠近队首的有效节点
if (s == null || s.waitStatus > 0) {
s = null;
for (Node p = tail; p != node && p != null; p = p.prev)
if (p.waitStatus <= 0)
s = p;
}
if (s != null)
LockSupport.unpark(s.thread);
}
- await方法
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
state未减到0,执行doAcquireSharedInterruptibly方法,否则继续执行线程后面的代码
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
将线程放入队列,队列不存在还会初始化(会创建虚拟头节点,waitstates是0)
final Node node = addWaiter(Node.SHARED);
try {
for (;;) {
获取当前线程的前一个线程节点
final Node p = node.predecessor();
前驱结点为头节点,尝试获取资源
if (p == head) {
int r = tryAcquireShared(arg);
r>=0,说明countdown已经减为0了,当前线程可以继续执行后面的方法
if (r >= 0) {
将当前节点线程设置为头节点,唤醒后面的线程
setHeadAndPropagate(node, r);
p.next = null; // help GC,回收节点
return;
}
}
将当前线程放在一个状态有效的线程节点后面,如果前驱节点已经是signal状态,则可以阻塞当前线程
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
}
响应线程中断
catch (Throwable t) {
cancelAcquire(node);
throw t;
}
}
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head; // Record old head for check below
设置新的头节点
setHead(node);
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
获取下一个线程节点,尝试唤醒
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
}
}
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
return true;
前驱节点线程已经被取消了,需要向前找到waitStatus <=0的节点
if (ws > 0) {
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
设置前驱节点线程状态为signal
pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
}
return false;
}