在处理异常时,在Java文档中降级ReentrantReadWriteLock的示例看起来非常不安全。我试着写一个简单的类来简化它。你看到有什么可能失败的案例吗?
我从并发的角度寻找一个回顾,比如如果在降级之前在嵌套锁中抛出异常,这段代码可能会失败。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
public class RWLockWrapper implements AutoCloseable {
private final ReadWriteLock rwl;
private Lock current;
//RAII
public RWLockWrapper(ReadWriteLock rwl) {
this.rwl = rwl;
this.current = rwl.writeLock();
this.current.lock();
}
public void downgrade() {
final Lock read = rwl.readLock();
read.lock();
try {
current.unlock();
} finally {
current = read;
}
}
@Override
public void close() {
current.unlock();
}
}像这样使用:
try (RWLockWrapper lock = new RWLockWrapper(rwl)) {
//write locked
lock.downgrade();
//read locked
}发布于 2014-09-03 23:51:42
代码的并发性/完整性以及显示它的使用方式都很好。
另一方面,这个设计是很值得怀疑的.我建议您不要使用此模式。
如果您要使用它(这里的评论说它已经使用了),那么我建议您更改名称。它不是包装器,因为您实际上无法通过包装器访问锁。相反,它是一个“锁定的会话”,可以关闭,并被降级。下面的代码看上去/读起来更好:
try (WriteLockedSession sessionlock = new WriteLockedSession(rwl)) {
//write locked
writelock.downgrade();
//read locked
}这表明构造函数启动写锁,并且会话是“可关闭的”。它也可以被降级。
任何语言中的并发性都是复杂的。Java有四种有详细说明的机制:
volatilesynchronizedjava.util.concurrent.* atomic.*微锁定系统locks.*宏锁定系统正确使用这些“系统”将允许安全操作。
当事情变得不规范时,问题就会开始发生,并与标准的使用模式背道而驰。当人们无法“看到”并发控制时,就会出现bug。
您的类强制执行出乎意料的编码实践:
最后一点意义重大..。ReadWriteLock没有指定锁的实现细节,它只是一个接口。此外,它还明确表示实现可以施加限制。:
尽管读写锁的基本操作是直截了当的,但实现必须作出许多决策.:
您的代码假设上面的假设只是有效的,但这是一个错误的假设。
我建议您更改代码以处理并发包中提供的实际ReentrantReadWriteLock实现。它确实支持这些东西。
此外,降级方法中的以下代码也是不必要的:
try { current.unlock(); } finally { current = read; }
这可能只是:
current.unlock();
current = read;unlock()不能抛出异常。如果是这样的话,Java中的其他东西也会被破坏。try/finally块表示您正在以某种方式保护锁,但它只是软绵绵。
指出这些问题后,考虑另一种选择.
那么,标准模式到底有什么问题呢?
考虑到这一点:
ReentrantReadWriteLock rwl = .....
Lock lock = rwl.writeLock();
lock.lock();
try {
rwl.readLock().lock();
lock.unlock();
lock = rwl.readLock()
} finally {
lock.unLock();
}上面有一个try
https://codereview.stackexchange.com/questions/61702
复制相似问题