V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ceshi123
V2EX  ›  Java

AQS 公平锁真的完全公平吗?

  •  
  •   ceshi123 · 2020-11-20 10:10:45 +08:00 · 3004 次点击
    这是一个创建于 1490 天前的主题,其中的信息可能已经有所发展或是发生改变。

    AQS 中获取公平锁的代码如下( jdk1.8 ): protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } }

    如果有三个线程来获取公平锁,第一个线程获取成功,第二与第三个线程走到 hasQueuedPredecessors(),都判断出为 false(此时队列为空,他们都可以获取锁),第二个线程继续走(第三个线程时间片到了,停住),获取锁失败(因为锁已经被第一个线程获取了),那就乖乖的去排队,构造头结点与自己的节点,此时 sync 队列为: head → node2,node2 → head,然后第二个线程又来抢占锁(源码中有个 for 循环),走到 hasQueuedPredecessors(),判断出也为 false (因为自己就是队列中的第二个节点,是有资格抢锁的),此时线程一释放了锁,那么第二个线程与第三个线程同时抢锁,锁是有可能被三个线程抢到了。

    那么这是不是违背了公平锁的概念,或者公平锁并不是绝对的公平,因为第二个线程已经在队列里面排好了队,也该是自己拿到锁,结果锁被第三个线程拿走了。

    麻烦各位大神解惑一下!!!

    8 条回复    2020-11-20 14:38:26 +08:00
    ceshi123
        1
    ceshi123  
    OP
       2020-11-20 11:59:46 +08:00
    我擦,大神呢
    yamasa
        2
    yamasa  
       2020-11-20 12:28:18 +08:00
    我觉得 tryAccquire 的这一段注释可以解答这个问题了:

    Likewise, it is possible for another thread to win a race to enqueue after this method has returned {@code false}, due to the queue being empty.
    ceshi123
        3
    ceshi123  
    OP
       2020-11-20 13:27:06 +08:00
    @yamasa 那其实它在极端场景下是并不是完全公平的
    yamasa
        4
    yamasa  
       2020-11-20 13:48:45 +08:00
    @ceshi123 对 而且可以说对于绝大部分场景,非公平的 performance 都更好
    THESDZ
        5
    THESDZ  
       2020-11-20 13:55:15 +08:00
    大部分的程序只会考虑绝大多数的情况,因为要考虑所有情况或者极端情况的话,成本>>收益
    THESDZ
        6
    THESDZ  
       2020-11-20 13:56:01 +08:00
    @THESDZ #5 如果的确要考虑极端情况,通常情况是通过"事后"补救
    1194129822
        7
    1194129822  
       2020-11-20 14:24:07 +08:00
    你这理解不对,首先说一下,公平只是相对的公平,所有公平模式,就是如果前面有线程排队就加入队尾,而非公平模式,就是线程直接尝试获取锁,获取失败才排队。但是线程本身的执行是没有顺序和优先级的。如果线程 2 因为 os 调度,一直得不到运行,可能一直永远排队。
    wysnylc
        8
    wysnylc  
       2020-11-20 14:38:26 +08:00
    公平是相对的而且不同的角度也会有不同见解
    无序的争抢才是高效
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3397 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 11:04 · PVG 19:04 · LAX 03:04 · JFK 06:04
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.