CountDownLatch
核心类:
private final Sync sync;
继承AQS
AbstractQueuedSynchronizer
核心方法:
await() 阻塞线程 , 直到同步状态status 变成0,线程才会被唤醒或打断抛出打断异常;
countDown()
sync.releaseShared(1); 内部调用releaseShared(1)方法,status减一;
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
倒数计时器
CountDownLatch 内部的Sync类, 重新实现了 tryAcquireShared()方法;
AQS的原方法是个空方法,内部直接抛出一个异常;
protected int tryAcquireShared(int arg) {
throw new UnsupportedOperationException();
}
判断是否阻塞线程
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
//如果前继节点的waitStatus值是SIGNAL,即-1, 则 当前线程需要被阻塞;
return true;
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
// waitStatus > 0 ,即waitStatus 只会是1,CANCELLED,表示已取消,此节点无效了, 通过一个自旋,一直想前找waitStatus 不大于0的节点,并将找到的有效前继节点指向当前线程所在的节点;
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
// 此时, waitStatus的值只会是-2或-3,即 CONDITION 或 PROPAGATE, 则通过CAS更新状态值为-1
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
总结下来就是,之前有效前继节点的waitStatus值是SINGAL (-1)时,才会阻塞当前线程;
通过
cancelAcquire()方法,取消继续获取锁;
步骤:
- node.thread = null; 将node内的Thread属性置空;
- 跳过无效的前继节点 =》通过自旋,找到有效的前继节点 pred ,即 前继节点的waitStatus 不大于0;
-
node.waitStatus = Node.CANCELLED; 状态置位1
- 记录一下 pred.next , 注意,此时pred.next 并不一定指向node;
- tail 尾指针指向 node,即node是尾部节点, 则通过CAS将tail指向其有效前继节点 preNode
-
compareAndSetNext(pred, predNext, null); 通过CAS比较, pred的后继指向是否仍然是predNext。如果仍然是,则置空,结束;