可重入锁条件公平性

问题描述 投票:0回答:2

我对

ReentrantLock
Condition
感到困惑。这是文档:

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

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

根据最新的项目符号,公平性带来了信令上锁重新获取的明确顺序。

但是第一个项目符号等待线程以 FIFO 顺序发出信号的含义是什么?我认为在这种情况下,信令仅意味着“发信号”,这意味着它按照 FIFO 顺序“取消驻留”线程,但唤醒时的实际重新请求顺序由公平性决定。

HotSpot 内部有大量的工作人员与 cxq 和等待队列相关,我对此不太了解(不幸的是)。


问题

等待线程按 FIFO 顺序发出信号是否意味着等待线程按照其停放顺序取消停放(即使锁本身不公平)?

公平性是否提供了必要的重新征用排序保证,因为在一般情况下存在取消公园重新获得竞争?

java multithreading jvm jvm-hotspot
2个回答
6
投票

正如'公平'和'不公平'锁内部存储的差异中所解释的,“公平”和“不公平”之间的实际区别不是队列的组织,而是在不公平模式下,线程试图获取即使队列中已经有等待线程,锁定也可能成功。这样的超车线程根本不会和队列交互。

调用

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

发出信号的线程可能会被取消停放,但也有可能它尚未停放。无论哪种情况,它都必须重新获取锁,并且这种重新获取受到锁的公平性保证。当线程调用

signal
时,它必须拥有锁。因此,有信号的线程无法立即成功。当锁被释放时,多个线程之间可能会出现竞争。

但是对于某个条件,按 FIFO 顺序发出信号意味着,当两个或多个线程正在等待同一条件并且其中一个线程收到信号时,它将成为等待时间最长的线程,并且其他线程都无法超越,即使对于非公平锁也是如此。只有当多个线程收到信号或其他线程未等待条件时才尝试获取锁,非公平锁的获取顺序是任意的。此外,正如链接的答案所提到的,即使在公平锁上,

tryLock()
也可能会超越。


1
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.