一般的な参照:書き込みロックの詳細な解釈ReentrantReadWriteLock
読み取りと書き込みは、複数のリーダースレッドから同時にアクセスできますが、ライタースレッドがアクセスすると、すべてのリーダースレッドと他のライタースレッドがブロックされます。
結論として:
- 公平性の選択:不公平性(デフォルト)と公平なロック取得方法をサポートしますが、スループットは公平性よりも不公平です。
- 再入可能性:再入可能性をサポートします。同じスレッドは、読み取りロックを取得した後に再度取得できます。同じスレッドは、書き込みロックを取得した後に書き込みロックを再度取得できます。また、同時に読み取りロックを取得することもできます。
- ロックのダウングレード:最初に書き込みロックを取得し、次に読み取りロックを取得してから書き込みロックを解放するという順序に従って、書き込みロックを読み取りロックにダウングレードできます。
読み取り/書き込みロックを完全に理解できるようにするには、いくつかの問題を理解できる必要があります。
- 読み取り/書き込みロックはどのようにして読み取り/書き込みステータスを個別に記録しますか?
- 書き込みロックはどのように取得および解放されますか?
- 読み取りロックはどのように取得および解放されますか?
1.書き込みロック:排他ロックです
1.書き込みロックの取得tryAcquire:書き込みロックを複数のスレッドで同時に取得することはできません。明らかに、書き込みロックは排他ロックであり、書き込みロックの同期セマンティクスは、AQSのtryAcquireメソッドを書き換えることによって実現されます。
tryAcquireにおいて、あるexclusiveCount int値有する(C)法、EXCLUSIVE_MASKを:同期状態の上位16ビットを示すために使用された回数を読み取りロックを取得し、同期状態の下位16ビットは書き込みロックの取得数を示すために使用されます。
tryAcquireの主なロジックは、読み取りロックがリーダースレッドによって取得された場合、または書き込みロックが他の書き込みスレッドによって取得された場合、書き込みロックの取得は失敗します。それ以外の場合、取得は成功して再入力をサポートし、書き込みステータスが増加します。
2.書き込みロック解除tryRelease:AQSのtryReleaseメソッドをオーバーライドして書き込みロック解除
ソースコードの実装ロジックは基本的にReentrantLockの実装ロジックと同じですが、書き込み状態を減らすには、現在の同期状態から書き込み状態int nextc = getState() - releases;
を直接差し引くだけでよいことに注意してください。理由は、先ほど述べた書き込み状態が同期状態の下位16ビットで表されます。
2.読み取りロック:排他的ロックではない:共有ロック
読み取りロックは排他ロックではありません。つまり、ロックは複数のリーダースレッドによって同時に取得できます。これは共有ロックです。
共有同期コンポーネントの同期セマンティクスを実現するには、AQSのtryAcquireSharedメソッドとtryReleaseSharedメソッドを書き直す必要があります。
1.読み取りロックの取得はtryAcquireSharedを実装します。
書き込みロックが他のスレッドによって取得されると、読み取りロックの取得は失敗します。それ以外の場合、取得は成功し、CASを使用して同期ステータスを更新します。
2.読み取りロック解放tryReleaseSharedの実装:
読み取りロック解除は、同期状態から読み取り状態を減算します。
3.ロックダウングレード:
読み取り/書き込みロックはロックのダウングレードをサポートします:最初に書き込みロックを取得し、次に読み取りロックを取得してから書き込みロックを解放するという順序に従います。書き込みロックは読み取りロックにダウングレードできますが、ロックのアップグレードはサポートされていません(読み取りロックを書き込みにアップグレードすることはできません)ロック);
4.要約:
不公平と公平の最大の違いは、書き込みロックの取得にあります。
- で不公平な戦略、書き込みロックの獲得は決してキューに登録する必要はありません。ほとんどの場合、書き込みロックに関わる作業時間は、読み取りロックよりもはるかに長いので、これは、リアルタイムのパフォーマンスの最適化を考慮しています、頻度は読み取りロックの頻度よりもはるかに低く、ライタースレッドが常に空腹になるのを防ぎます。
- ReentrantReadWriteLockの特別な機能は、int値を使用して2つの異なる状態を表すことです(下位16ビットは書き込みロックの再入可能数を表し、上位16ビットは読み取りロックの使用数を表します)。 2つの内部クラスを介して同時に実装されます。2つのAPIのコア部分と共有/排他ロックの間に違いはありません。