关于 AQS 中的 acquire 方法的一点疑惑

2021-11-11 10:05:00 +08:00
 fatyoung

public final void acquire(int arg) {

    if (!tryAcquire(arg) &&

        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

        selfInterrupt();

}

这是 AQS 中的模板 acquire 方法,里面有个 acquireQueued 方法:

final boolean acquireQueued(final Node node, int arg) {

    boolean failed = true;

    try {

        boolean interrupted = false;

        for (;;) {

            final Node p = node.predecessor();

            if (p == head && tryAcquire(arg)) {

                setHead(node);

                p.next = null; // help GC

                failed = false;

                return interrupted;

            }

            if (shouldParkAfterFailedAcquire(p, node) &&

                parkAndCheckInterrupt())

                interrupted = true;

        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

代码逻辑会判断当前节点的前驱结点是不是头结点( p == head ),如果是才去获取锁。我看了下 ReentrantLock 中的非公平锁也会走到这一段逻辑来,那这还叫非公平锁吗? 为什么非公平锁也要去 CLH 队列判断当前线程结点是不是头结点?

592 次点击
所在节点    程序员
4 条回复
fatyoung
2021-11-11 10:11:45 +08:00
还是说非公平锁只在第一次抢占时才是非公平的? 如果抢占失败进入 CLH 队列,后续跟公平锁一样都是需要判断队列头结点才能继续抢占?
cweijan
2021-11-11 10:12:15 +08:00
非公平锁是调用 lock 的时候立刻执行一次 cas, 如果成功就获取锁, 不获取就走和公平锁一样的逻辑.
fatyoung
2021-11-11 10:14:36 +08:00
@cweijan 了解了,谢谢老哥
shinyruo2020
2021-11-13 20:28:25 +08:00
仔细看源码就知道了,实际上在一开始,非公平锁会多进行两次 cas ,并不只是一次

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/814594

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX