gpt4 book ai didi

java - 检查 `ReentrantReadWriteLock` 中是否拥有 readLock

转载 作者:行者123 更新时间:2023-12-01 09:07:44 26 4
gpt4 key购买 nike

我在尝试使用 ReentrantReadWriteLock 时出现了一些密切相关的问题。控制对具有许多不同读写操作的相当复杂的数据结构的访问。根据文档中的示例,我获取了读锁和写锁,并且我正在使用它们(据我所知)成功管理对此数据结构的并发访问。然而,在调试另一个问题时,我注意到有时我会在同一线程中获取多个读锁。其基本原因是我有许多复杂的查询调用更简单的查询(请参见下面的示例)。复杂的查询可以被认为是一个事务,即,在 getVersion() 和访问 myQuery 中的 data 之间不应该有任何写入操作>。当前的解决方案有效,但这意味着在代码中的某些地方,同一线程将拥有多个读锁。我注意到 write 等效项有一个 isHeldByCurrentThread() 方法,但奇怪的是在 readLock 中没有这个方法。我找不到以下内容:

  • 在同一个线程中拥有多个读锁是否不好(风格差、性能差或 future 出现错误的风险)?
  • 不好用WriteLock.isHeldByCurrentThread检查错误(例如,期望写锁但不存在,或者作为释放写锁的条件)?
  • 如果出现此问题,是否有最佳实践来决定如何处理?我是否将 lockedAquired boolean 值传递给可能从已拥有锁的代码调用的方法,是否确保它们是唯一获取的,或者应该使用 ReadLock.tryLock()

这是代码示例:

public class GraphWorldModel {

//unfair RW Lock (default, see javadoc)
protected final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(false);
protected final ReentrantReadWriteLock.ReadLock readLock = rwl.readLock();
protected final ReentrantReadWriteLock.WriteLock writeLock = rwl.writeLock();

protected long versionID = 0;
protected Object data = null;

@Override
public long getVersion() {
long result = -1;
readLock.lock();
try {
result = this.versionID;
} finally {

readLock.unlock();
}
return result;
}
public ResultObject myQuery() {
//do some work
readLock.lock();
try {
long version = getVersion();
ResultObject result = new ResultObject(this.data, version);
//note: querying version and result should be atomic!
} finally {
readLock.unlock();
}
//do some more work
return result;
}
}

最佳答案

  • is it bad (poor style, performance or risk of future bugs) to have multiple read locks in the same thread?

我想说这是有问题的风格。首先,正如 @JBNizet 指出的那样,尝试再次获取已经拥有的锁是没有问题的。锁只是将读取器计数增加 1,然后在最终解锁时将其减少。

但是,这确实意味着您必须跨越内存屏障( volatile 读取)才能更新共享锁统计信息,这意味着性能会受到影响。这取决于此代码的执行频率是否会产生任何明显的性能差异。

然而,就错误而言,有一个很大的问题。如果您只是谈论只读锁,那么我认为出现错误的可能性不会更大。实际上尝试解决双锁问题(见下文)可能会有更大的风险。但在您的代码中,try/finally 逻辑可确保正确使用锁并在完成后解锁。

但是,如果您正在谈论混合读写锁,那么您需要了解以下代码死锁:

ReentrantReadWriteLock rrwl = new ReentrantReadWriteLock();
ReadLock readLock = rrwl.readLock();
WriteLock writeLock = rrwl.writeLock();
readLock.lock();
writeLock.lock();

或者至少它会停止,直到其他代码解锁读锁。如果您打算在代码中混合使用读锁和写锁,那么您必须防止双重锁定。

  • is is bad to use WriteLock.isHeldByCurrentThread to check for errors (e.g., expecting a write lock but none is present, or as a condition to release the write lock)?

这将为您的代码添加大量逻辑,这会带来更大的风险,但如果性能损失很大,则可能是值得的。也就是说,请参阅下面的替代方案。

  • is there a best practice to decide how to proceed if this is an issue? Do I pass a lockedAquired boolean to methods that may be called from code that already possesses a lock, do I ensure they are uniquely acquired, or should I use ReadLock.tryLock()?

我要做的是创建一个名为getVersionLocked()的内核方法。像这样的东西:

@Override
public long getVersion() {
readLock.lock();
try {
// NOTE: I refactored this to return out of the try/finally which is a fine pattern
return getVersionLocked();
} finally {
readLock.unlock();
}
}
public ResultObject myQuery() {
//do some work
readLock.lock();
ResultObject result;
try {
long version = getVersionLocked();
result = new ResultObject(this.data, version);
//note: querying version and result should be atomic!
} finally {
readLock.unlock();
}
//do some more work
return result;
}
// NOTE: to call this method, we must already be locked
private long getVersionLocked() {
return this.versionID;
}

然后您可以决定调用方法的锁定版本还是解锁版本,并且只执行一次readLock()

这样做的风险更大,因为您可能会在未持有锁时调用 getVersionLocked(),但我认为这是可以接受的风险。

关于java - 检查 `ReentrantReadWriteLock` 中是否拥有 readLock,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41127563/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com