ReadWriteLock中。了解从readLock升级到writeLock

时间:2016-05-07 10:03:43

标签: java multithreading readwritelock

考虑这个JDK标准接口:

public interface ReadWriteLock{
    public Lock readLock();
    public Lock writeLock();
}

B中。 Java中的Goetz并发实践中提到从readLock升级到writeLock是容易死锁的。

  

如果两个读者同时尝试升级到写锁定,   它们都不会使读取锁定。

令我困惑的是, 两个 读者试图升级。但即便是一位读者就够了,不是吗?如果读者试图升级它还没有释放读锁定。尝试使用读锁定获取写锁定是死锁。

因此,我认为提供升级操作在理论上甚至是荒谬的。或者也许实现可以解决这个问题?

1 个答案:

答案 0 :(得分:5)

听起来你正在考虑一个"读锁定"和#34;写锁定"是两个不同的锁组成一个读写锁。这并不是思考它的正确方法,即使API似乎暴露了这样的组合(通过提供方法来获得对&#34的写入;写入锁定"以及"读锁")。

(这一点让人感到困惑的是术语的重载"锁定" - 它既是动词又是名词,即,可以锁定 )。

不要认为ReadWriteLock的{​​{1}}方法和readLock方法返回实际的锁,而是考虑他们实际做的是返回一个抽象的机制允许获取不同类型的锁(在相同的,单个,读写锁机制上)。

读写锁(机制)是锁,可以通过两种方式锁定:读锁定写锁定。读写锁可以由一个或多个线程同时读锁定,也可以写锁定。它永远不会同时被读取和写入锁定。

  

如果读者试图升级它还没有释放读锁定。尝试使用读锁定获取写锁定是死锁。

写锁定比读锁定更强;它就像一个带有附加属性的读锁(没有其他线程也可以持有锁)。从读锁定升级到写锁定不是在另一个锁定已经被保持时获取一个锁定;相反,它是关于改变已经锁定在一个锁上的锁的类型。

因此,单个线程将其读锁升级为写锁没有概念上的问题。它只需要等到读锁的所有其他持有者在升级之前放弃它。在这种情况下不存在死锁的可能性。

例如,假设有三个线程--A,B和C,它们都具有读锁定锁。线程A尝试升级到写锁定。这意味着它必须等待B和C放弃它们的读锁定。这最终会发生,并且在那时线程A获得写锁(并且最终,线程A将放弃此锁)。

另一方面,考虑A和B是否都尝试升级到写锁定。这意味着他们都在等待另一个人放弃读锁定,这不会发生;对于线程A放弃读锁定,它首先需要获取写锁定,直到线程B放弃读取锁定才会发生这种情况,直到它获得写锁定为止,它才会被执行。在线程A放弃读锁定之前不会发生......依此类推。有一个僵局。

Java API不允许从读锁升级到写锁,因为这可以防止死锁情况。编写一个可以安全地升级锁类型的程序是可能的(如果有点棘手),但是Java API并不允许它。