2024-03-23  阅读(1)
版权声明:本文为博主付费文章,严禁任何形式的转载和摘抄,维权必究。 本文链接:https://www.skjava.com/mianshi/baodian/detail/1281134826

当线程调用 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 同步队列的情况如下: