ReadWriteLock
实施允许 ReentrantReadWriteLock
降级(以下示例中的tryLock()
始终返回true
):
void downgrade(final ReadWriteLock readWriteLock) {
boolean downgraded = false;
readWriteLock.writeLock().lock();
try {
// Always true, as we already hold a W lock.
final boolean readLockAcquired = readWriteLock.readLock().tryLock();
if (readLockAcquired) {
// Now holding both a R and a W lock.
assert ((ReentrantReadWriteLock) readWriteLock).getReadHoldCount() == 1;
assert ((ReentrantReadWriteLock) readWriteLock).getWriteHoldCount() == 1;
readWriteLock.writeLock().unlock();
downgraded = true;
try {
// Now do some work with only a R lock held
} finally {
readWriteLock.readLock().unlock();
assert ((ReentrantReadWriteLock) readWriteLock).getReadHoldCount() == 0;
assert ((ReentrantReadWriteLock) readWriteLock).getWriteHoldCount() == 0;
}
}
} finally {
if (!downgraded) {
// Never (we were holding a W lock while trying a R lock).
readWriteLock.writeLock().unlock();
}
assert ((ReentrantReadWriteLock) readWriteLock).getReadHoldCount() == 0;
assert ((ReentrantReadWriteLock) readWriteLock).getWriteHoldCount() == 0;
}
}
不允许以类似方式进行锁升级的想法是什么?下面的 Write 锁定的tryLock()
方法可以安全地返回true
,如果没有其他线程持有 Read ,则会造成死锁风险锁:
void upgrade(final ReadWriteLock readWriteLock) {
readWriteLock.readLock().lock();
try {
// Always false: lock upgrade is not allowed
final boolean writeLockAcquired = readWriteLock.writeLock().tryLock();
// ...
} finally {
readWriteLock.readLock().unlock();
}
}
答案 0 :(得分:3)
首先,请注意升级和降级在ReadWriteLock
的语义复杂性方面并不相同。
您不需要抵制争用以完成降级事务,因为您已经拥有锁定上升级最多的权限,并且因为您保证是当前执行降级的唯一线程。升级也是如此,因此支持升级的机制自然需要更复杂(或更智能)。
为了可以使用,升级机制需要防止死锁,以防两个读取线程同时尝试升级(或专门针对ReentrantReadWriteLock
,以防一个读取线程持有多个读锁定尝试升级)。此外,该机制需要指定如何处理失败的升级请求(它的读取锁定是否会失效),并且这样做甚至更不重要。
正如您现在可能已经看到的那样,在ReentrantReadWriteLock
中完全处理这些问题是不方便的,至少可以说(这仍然是.NET ReaderWriterLock
尝试的,我认为实际上是成功的做)。我的猜测是虽然final boolean writeLockAcquired = readWriteLock.writeLock().tryLock();
本可以在一些微不足道的情况下取得成功,但升级性仍然不足以满足普通使用 - 在足够严重的争用下,如果你失去了写作的竞争锁定,你在同一条船上,好像你解锁了读锁定并试图获得写锁定(让其他人潜入并获取其间的写锁定的机会)。
提供锁升级性的一个好方法是只允许一个线程尝试升级 - 这是ReentrantReadWriteUpdateLock
做的或者ReaderWriterLockSlim
做的事情。但是我仍然会推荐Java 8' StampedLock
作为: