可重入读写锁中的公平锁定

3
在B.Goetz的《Java Concurrency In Practice》第13.5节中提到:
在Java 5.0中,读锁更像一个信号量而不是锁,只维护活动读者的计数,而不是它们的身份。在Java 6中改变了这种行为,也跟踪了哪些线程已被授予读锁。这种变化的一个原因是,在Java 5.0下,锁实现无法区分请求第一次读锁和可重入锁请求的线程,这会使公平读写锁陷入死锁。
我的问题是:公平性有什么问题?为什么不公平的读写锁能够避免死锁?
您能解释一下他的意思吗?即在什么情况下,Java 5下的公平读写锁会导致死锁?如果它像一个Semaphore那样运作,为什么公平的Semaphore没有导致死锁?

3
你可能希望停下来思考一下,公平对于什么是“正确”的?在桌面或服务器环境中,进程通常会互相竞争以获取 CPU 时间。调度程序中的“公平性”确保每个竞争进程获得公平份额。但是在单个程序内,线程应该相互合作而不是相互竞争。当有工作需要完成时,哪个线程完成工作并不重要。如果池中有两个工作线程,但只有一个半线程的工作量需要完成,如果负载没有被“公平”分配,也不会有任何影响。 - Solomon Slow
在获取锁的上下文中,“公平性”表示竞争同一把锁的线程按照它们请求锁的顺序获取锁。 - bowmore
@bowmore,我知道调度程序中的“公平性”与互斥锁的“公平”实现并不完全相同,但它们共享相同的名称并非巧合。它们都旨在确保线程/进程在竞争资源时获得“公平”的访问。我对“公平”互斥锁的重要性提出了质疑,因为当我编写多线程代码时,我不希望我的线程公平竞争:我希望它们根本不竞争。这是一个难以实现的目标,但在我看来,在性能成为问题时值得努力。 - Solomon Slow
1个回答

8

如果实现不知道请求线程是否已经拥有锁,则在使用公平锁策略时,来自同一线程的新请求将排在之前的请求后面,可能是其他线程的请求。

如果在此可重入请求之前有来自其他线程的写请求,则它们无法前进,因为持有锁的线程也被阻塞等待其可重入请求,导致死锁。

不公平的锁定策略不会遇到这个问题,因为可重入请求可以插队(闯入),不需要等待之前的请求。

信号量不会遇到这个问题,因为它不是可重入的。


Semaphore不会受到这个问题的影响,因为它不是可重入的。嗯,这并不十分清楚。根据您的解释,我认为它们不会受到影响,因为没有“读”/“写”信号量。 - user2953119
@DmitriiBundin 我的意思是,同一线程从Semaphore请求另一个许可证应该获得第二个许可证,即使它已经获得了一个。显然也有可能陷入死锁状态,但这将是客户端的错误,而不是Semaphore实现的错误。 - bowmore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接