当线程调用 release()
释放锁时,完成锁释放后调用 unparkSuccessor()
唤醒后继节点的线程,这个方法里面有一个这样的逻辑判断,当该节点的 next 为空,或者状态为已取消,则 AQS 从 tail 节点开始往前搜索节点:
这里为什么要从 tail 节点开始呢?
我们知道一个线程获取锁失败后,会被包装成一个 Node 节点加入到 CLH 同步队列中:
如果 tail 没有被初始化或者设置 tail 节点失败都会走 enq()
,在这里我们考虑设置 tail 节点失败的情况,tail 节点失败说明有多个线程在设置 tail 节点,走 enq()
:
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) { // 1
t.next = node; // 2
return t;
}
}
}
}
有多个线程执行 enq()
方法加入 tail,而这个方法又没有采取任何同步手段来保护线程安全。所以在高并发的情况下可能会出现如下这种情况。
我们假定现在 CLH 同步队列的情况如下: