ReentrantReadWriteLock
を使用して、多数の異なる読み書き操作を持つかなり複雑なデータ構造へのアクセスを制御しようとしたときにポップアップした質問があります。ドキュメントの例では、読み書きロックを取得しましたが、私はこのデータ構造への同時アクセスを管理するために(私が知る限り)使用しています。しかし、別の問題をデバッグする際に、同じスレッドで複数の読み取りロックを取得することがあることに気付きました。これの基本的な理由は、より単純なクエリを呼び出す複雑なクエリが多数あることです(下記の例を参照)。複雑なクエリは、トランザクションとみなすことができます。つまり、getVersion()
とdata
へのアクセスは、myQuery
には書き込まれません。この現在の解決策は動作しますが、コード内のいくつかの箇所では、同じスレッドが持つ複数の読み取りロックを持つことになります。私は書き込み同等物がisHeldByCurrentThread()
メソッドを持っていることに気づいたが、これはreadLock
に奇妙に存在しない。私は以下を見つけることができませんでした:`ReentrantReadWriteLock`の読み込みロックの確認
- 同じスレッドで複数の読み取りロックを持つのは悪いですか(不良なスタイル、パフォーマンス、または将来のバグの危険性)?
WriteLock.isHeldByCurrentThread
を使用してエラーをチェックするのは悪いです(たとえば、書き込みロックが必要ですが、存在しないか、書き込みロックを解除する条件)。- これが問題になった場合の進め方を決めるベストプラクティスはありますか?
lockedAquired
ブール値を、すでにロックを持っているコードから呼び出すことができるメソッドに渡すのですか?それらが一意に取得されることを保証するのですか、または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;
}
}
ロックは、その名前が示すとおり、リエントラントです。あなたがすでにそれを所有しているときに再びそれを取得することは、まったく問題ではありません。あなたが持っているものは完璧です。 –