JAVA中REENTRANT LOCK中的公平参数的用途是什么?

Tar*_*run 0 java multithreading locking

我在查看可重入锁的 Java 文档时发现了以下文本:

锁的公平性并不能保证线程调度的公平性。因此,使用公平锁的许多线程之一可能会连续多次获得公平锁,而其他活动线程没有进展并且当前没有持有该锁。

根据我的理解,这意味着,如果操作系统调度程序调度相同的线程(之前获取锁)并且它尝试再次获取相同的锁,Java将允许它获取并且不会遵守公平参数值。有人可以告诉我公平参数的目的是什么以及在什么情况下应该使用它。
我只是在想它是否就像一个优先级值,这可能会影响调度程序但不能保证线程执行顺序。

Hol*_*ger 7

在 na\xc3\xafve 视图中,使用公平锁的线程的行为类似于

\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n
线程\xc2\xa01线程\xc2\xa02线程\xc2\xa03
获得做一点事做一点事
关键部分尝试获取做一点事
关键部分被阻止尝试获取
发布获得被阻止
做一点事关键部分被阻止
尝试获取发布获得
被阻止做一点事关键部分
获得做一点事发布
\n
\n

\xe2\x80\x9cTry Acquire\xe2\x80\x9d 指的是lock()由于另一个线程拥有锁而不会立即成功的调用。它并不指tryLock()一般情况下哪个\xe2\x80\x99t 公平。

\n

在此 na\xc3\xafve 视图中,线程按顺序获取锁 \xe2\x80\x9cThread\xc2\xa01\xe2\x80\x9d、\xe2\x80\x9cThread\xc2\xa02\xe2\x80\x9d ,\xe2\x80\x9cThread\xc2\xa03\xe2\x80\x9d,因为\xe2\x80\x99是获取尝试的顺序。特别是当 \xe2\x80\x9cThread\xc2\xa01\xe2\x80\x9d 尝试在 \xe2\x80\x9cThread\xc2\xa02\xe2\x80\x9d 释放锁时获取锁时,它不会 \xe2 \x80\x99t 会像不公平锁一样超越,而是 \xe2\x80\x9cThread\xc2\xa03\xe2\x80\x9d 会获得它,因为它等待的时间更长。

\n

但是,正如文档所说,线程调度是不公平的。因此,可能会发生以下情况。

\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n
线程\xc2\xa01线程\xc2\xa02线程\xc2\xa03
获得做一点事做一点事
关键部分做一点事
关键部分
发布
做一点事
获得尝试获取尝试获取
关键部分被阻止被阻止
关键部分被阻止被阻止
\n
\n

空单元格代表线程根本没有获得任何 CPU 时间的阶段。线程数可能多于 CPU 核心数,其中包括其他进程的线程。操作系统甚至可能更愿意让 \xe2\x80\x9cThread\xc2\xa01\xe2\x80\x9d 继续在核心上运行,而不是切换到其他线程,仅仅是因为该线程已经运行并且切换需要时间。

\n

一般来说,尝试预测达到某个点(例如前面工作负载获取锁)的相对时间并不是一个好主意。在具有优化 JIT 编译器的环境中,即使两个线程使用完全相同的输入执行完全相同的代码,也可能具有完全不同的执行时间。

\n

因此,当我们无法预测尝试时间时lock(),坚持以不可预测、未知的顺序获取锁并不是很有用。开发人员仍然希望公平的一种解释是,即使结果顺序不可预测,也应该确保每个线程都取得进展,而不是在其他线程反复超越时无限等待锁定。但这又让我们回到了不公平的线程调度;即使根本没有锁,也不能保证所有线程都能取得进展。

\n

那么为什么公平选项仍然存在呢?因为有时,人们对大多数情况下的工作方式感到满意,即使没有强有力的保证它总是会这样工作。或者简单地说,因为如果它不存在,开发人员会反复询问它。支持公平性不会花费太多成本,并且不会影响非公平锁的性能。

\n

  • 没有 CPU 时间是“没有进展”的最常见原因。其他原因可能是“运行异常缓慢”,因为 JIT 尚未启动,或者“因堆栈上代码替换而停止”,因为 JIT *确实*启动了,或者在分配尝试期间“等待垃圾收集器”。 (2认同)