Java 5.0 より前には、同期ロック (組み込みロック) と揮発性ロックのみが存在しました。Java 5.0 以降は、表示ロック ReentrantLock が導入されました。
リエントラントロックの概要
ReentrantLock は、組み込みロックとは異なり、使用するたびに明示的なロックとロック解除を必要とし、より高度な機能 (フェア ロック、条件付きロック、および中断可能) を提供します。 ReentrantLock の実装により、デッドロックの活性化の問題を効果的に回避できます。
ロックインターフェイス:
次のようにコードをコピーします。
パブリック インターフェイス ロック {
// ロックが取得されるか中断されるまでブロックします
ボイドロック();
//ロックが取得されるまでブロックするか、割り込み時に例外がスローされる
void lockInterruptibly() は InterruptedException をスローします。
//ロックが利用可能な場合のみ取得し、それ以外の場合は直接返します
ブール値 tryLock();
//指定された時間内にロックが利用可能な場合にのみロックを取得し、それ以外の場合は直接戻り、中断された場合に例外をスローします。
boolean tryLock(長時間、TimeUnit 単位) は InterruptedException をスローします。
void ロック解除();
//このロックにバインドされた条件を返します
条件 newCondition();
}
ロックの使用
次のようにコードをコピーします。
ロック lock = new ReentrantLock();
ロック.ロック();
試す{
// オブジェクトのステータスを更新します
}ついに{
//ここで注意してください、ロックを解除するには最終的にコードブロックが必要です
//そうしないと、デッドロックやその他のアクティビティの問題が発生しやすくなります。
ロック解除();
}
リエントラントロック機能
ポーリング ロックと時間指定ロック
ポーリング可能で時間指定可能なロック要求は、tryLock() メソッドによって実装されます。これは、無条件のロック取得とは異なり、ReentrantLock には柔軟なフォールト トレラント メカニズムが備わっており、デッドロックの多くのケースは、シーケンシャル ロックによって発生し、異なるスレッドが取得を試みます。ロック時にブロックされ、すでに保持しているロックが解放されず、最終的にデッドロックが発生します。 tryLock() メソッドがロックを取得しようとしたとき、そのロックがすでに別のスレッドによって保持されている場合は、ブロックして待機するのではなく、設定メソッドに従ってすぐに戻ります。同時に、保持しているロックはその後解放されます。その結果、デッドロックを回避するためにリトライまたはキャンセルが実行されます。
公平性
ReentrantLock コンストラクターには、公平なロックと不公平なロック (デフォルト) という 2 つのオプションがあります。いわゆる公平なロックでは、スレッドはリクエストを発行した順序でロックを取得し、キュー ジャンプは許可されませんが、不公平なロックの場合は、スレッドがロックの取得を要求したとき、ロックが使用可能な場合はキュー ジャンプが許可されます。 、その後、このスレッドはキュー内の待機中のスレッドをスキップし、ロックを取得します。私たちは通常、すべてのロックが不公平であることを望んでいます。ロック操作を実行する場合、公平性によりスレッドの一時停止とスレッドの回復のオーバーヘッドによりパフォーマンスが大幅に低下するためです。状況を考えてみましょう。スレッド A がロックを保持しており、スレッド B がロックを要求しているため、スレッド A がロックを解放するとスレッド B が起動され、同時にロックを再度取得しようとします。 C もこのロックの取得を要求すると、B スレッドが完全に起動される前に、C スレッドがこのロックを取得、使用、解放する可能性があります。これは、B がロックを取得する瞬間 (B がウェイクアップした後にのみロックを取得できる) が遅れることがなく、スループットも向上します。ほとんどの場合、不公平なロックのパフォーマンスは公正なロックのパフォーマンスよりも高くなります。
ロック取得操作は中断可能
lockInterruptibly メソッドは、割り込みへの応答を維持しながらロックを取得するため、他の種類の割り込み不可能なブロック操作を作成する必要はありません。
読み取り書き込みロック読み取り書き込みロック
ReentrantLock は標準のミューテックス ロックであり、一度に 1 つのスレッドのみがロックを保持できます。読み取り/書き込みロックは異なります。2 つの Lock オブジェクトが公開され、1 つは読み取り操作に使用され、もう 1 つは書き込み操作に使用されます。
次のようにコードをコピーします。
パブリック インターフェイス ReadWriteLock {
/**
* 読み取りに使用されるロックを返します。
*
* @return 読み取りに使用されるロック。
*/
ロック readLock();
/**
* 書き込みに使用されるロックを返します。
*
* @return 書き込みに使用されるロック。
*/
ロック writeLock();
}
オプションの実装:
1. リリース優先度
2. 読み取りスレッドがインラインでジャンプする
3. リエントラント性
4.ダウングレード
5.アップグレード
ReentrantReadWriteLock は ReadWriteLock インターフェイスを実装し、コンストラクターは公平なロックと不公平なロックという 2 つの作成メソッドを提供します。読み取り/書き込みロックは、読み取りが多く書き込みが少ない状況に適しており、より優れた同時実行性を実現できます。
サンプルのコピーコードは次のとおりです。
パブリック クラス ReadWriteMap<K, V> {
プライベート Map<K, V> マップ;
プライベート最終 ReadWriteLock ロック = new ReentrantReadWriteLock();
プライベート最終ロック readLock = lock.readLock();
プライベート最終ロック writeLock = lock.writeLock();
public ReadWriteMap(Map<K, V> マップ) {
this.map = マップ;
}
public V get(K キー) {
readLock.lock();
試す {
戻りマップ.get(キー);
} ついに {
readLock.unlock();
}
}
public void put(K キー, V 値) {
writeLock.lock();
試す {
マップ.put(キー, 値);
} ついに {
writeLock.unlock();
}
}
}