可重入锁条件公平

问题描述

我对 reentrantlockCondition 感到困惑。这是文档:

  • 等待线程按 FIFO 顺序发出信号。

  • 等待返回的线程重新获取锁的顺序 方法与最初获取锁的线程相同,后者 在认情况下未指定,但对于公平锁有利于那些 等待时间最长的线程。

根据最新的子弹,公平性带来了对信令重新获取锁的明确规定。

但是第一个项目符号的含义是什么等待线程以 FIFO 顺序发出信号?我认为在这种情况下,信令只是“发出信号”,意味着它以 FIFO 顺序“解除”线程,但唤醒时的实际重新获取顺序受公平性控制。

There are pretty large amount of staff 与 HotSpot 内部的 cxq 和等待队列相关联,我不太了解(不幸的是)。


问题

等待线程以 FIFO 顺序发出信号是否意味着等待线程以其停放的相同顺序解除停放(即使锁本身是不公平的)?

公平性是否提供了重新获取排序保证,因为在一般情况下存在 unpark-require 竞争?

解决方法

Difference in internal storing between 'fair' and 'unfair' lock中所解释的,“fair”和“unfair”之间的实际区别不在于队列的组织方式,而是在不公平模式下,尝试获取锁的线程可能会成功,即使有已经在队列中等待线程。这样的超车线程根本不会与队列交互。

调用 await 上的 Condition 方法之一的线程必须已经拥有关联的锁并将释放它,以便另一个线程可以获取它,满足条件并调用 signalsignalAll。因此该线程必须将自己排入队列,以便另一个线程知道要向哪个线程发出信号。当调用 signal 时,从 FIFO 中取出等待该条件时间最长的线程。

发出信号的线程可能会被解除停放,但也有可能它还没有停放。在任何一种情况下,它都必须重新获取锁,并且这种重新获取受锁的公平保证的约束。当线程调用 signal 时,它必须拥有锁。因此,发出信号的线程不能立即成功。当锁被释放时,可能会出现多个线程之间的竞争。

但是一个条件的 FIFO 顺序中的信号意味着当两个或多个线程正在等待相同的条件并且一个被发出信号时,它将是最长的等待线程并且其他线程都无法超越,即使对于不公平的锁.只有当多个线程被发信号或者其他线程,不等待条件,尝试获取锁时,不公平锁的获取顺序是任意的。此外,正如链接的答案所提到的,tryLock() 甚至可能在公平锁上超车。

,

阅读 ReentrantLock (Java 12) 的源代码,我们可以看到公平和不公平的 ReentrantLock 只有很小的区别。不同之处在于扩展 java.util.concurrent.locks.AbstractQueuedSynchronizer 的类。一种情况是 FairSync,另一种情况是 NonfairSync。两者都在 ReentrantLock 中定义,唯一的区别是 FairSync 在方法 tryAcquire 中实现了另一项检查。 阅读代码似乎在最佳条件下也在非公平 ReentrantLock FIFO 中受到尊重,但由于取消、超时或类似情况,无法保证这一点。在公平的 ReentrantLock 中,在获取锁之前的任何线程(如果从队列中解除停放也是如此)重新检查是否存在较旧的线程。 我不确定是否理解第二个问题,但请注意释放锁的线程从队列中解除了一个线程。此外,如果释放锁的线程将队列中的旧线程解停,这还不足以避免 starvation,因为第三个线程可能需要在退出线程解停等待线程之前并发获取锁。在公平模式下,每次新线程尝试获取锁时都会检查所有等待的线程,并且该被授予者 FIFO 并避免饥饿。

等待线程的外部中断不会改变队列顺序。