blog

論文は、最も複雑な並行処理ツールクラスの読み取りと書き込みロックのソースコードを理解する

前の記事は、クラスの実装では、AQSの使用を分析し、今日は最後と最も複雑な1。1つだけのスレッドをサポートするために同じ瞬間の主な機能は、ロックを持っていますが、ほとんどの場合、次のとおりです。...

Jun 22, 2020 · 4 min. read
シェア

前回の記事では、AQSの実装クラスの使い方を分析しましたが、今日は最後の、そして最も複雑な実装クラスであるReentrantReadWriteLockについて説明します。

主な機能

ReentrantLock同時に1つだけのスレッドをサポートするためにロックしていますが、ほとんどの場合、データへのアクセスではなく、変更、アクセスれ、データを変更することはありません他のスレッドがリソースにアクセスするために影響を与えないので、リソースを所有する排他的な方法であってはならないが、システムのスループットを向上させるためにリソースへの同時アクセスをサポートする方法の共有。

ReentrantReadWriteLock読み書きロッククラスは、同時に複数の読み取りロックをサポートし、スレッドが書き込みロックを保持しているときは、他のすべてのスレッドはアクセスできません。

次に、読み取りキューの長さ、待ちキューの長さ、書き込みロックの解放などの補助関数があります。

主な構造

readerLock、writerLockはReentrantReadWriteLockの読み込みロック、書き込みロック機能をサポートするためにロック、アンロックメソッドを提供していますが、これらのメソッドはすべて直接syncのメソッドを呼び出しているので、最終的にはソースコードのSync実装を見る必要があります。

Syncソースコードの解析

Syncの実装はいくつかのツールクラスの実装よりもはるかに複雑ですが、目的は状態を維持することです。しかし、ここでのSyncは読み取りロックと書き込みロックを実装する必要があり、ここではステートに読み取り識別子と書き込み識別子を実装する方法を説明します。

Int型のステートは32ビットで、最初の16ビットをリード・ロックの統計情報として、最後の16ビットをライト・ロックの統計情報として使用します。

各スレッドが正常に読み取りロックを取得し、つまり、readLock().lock()の成功は、ロックが解放されるたびに、2、つまり、16ビットで右にシフトされた状態の読み取りロックの数をカウントするために、2から減算されます状態に追加されます。

各スレッドは、1を追加する状態のロックを書き込むために取得するには、ロックを追加するために繰り返すことができますが、唯一のwriterLockマークとして状態の最後の16ビットは、つまり、writerLockロックの回数は2 ******** - 1まで、ロックが読み取りロックのマークになる場合、書き込みロックの数の統計に状態&2-1、書き込みロックの数を聞かせて。具体的なソースコードは次のとおりです:

Sync はこの原則をサポートするためにいくつかのメソッドを実装しています:

tryRelease(intのリリース):排他的ロックを解放し、現在のスレッドの単純な判断の実装は、ロックスレッドの所有者ではない、状態マイナスリリースの値であり、それ以外の場合は例外、状態のリリースが0に等しい場合は、nullにロックの所有者を更新します;

tryAcquire(int acquires): 排他ロックの取得を試みます。

1、状態の値が0に等しいかどうかを判断し、それがないロックが0に等しい場合は、状態を変更しようとすると、成功または失敗を得るためにロックの成功を変更します。

2、0に等しくない場合、取得した排他ロックの数が0に等しいか、排他スレッドが現在のスレッドでない場合はfalseを返し、追加されたロックの数が追加されたロックの最大数を超える場合は例外がスローされます。

読み取りロック、つまり共有ロックは少し複雑で、Sync には他に HoldCounter と ThreadLocalHoldCounter という 2 つのクラスがあり、ローカル・スレッド・クラスを使って各スレッドが取得した読み取りロックの数を保持します。

tryAcquireShared(int未使用):共有ロックを取得し、主な手順 1は、書き込みロックがあるかどうかを判断し、直接リターン失敗があり、2、書き込みロックによって保持されていないその後、状態の値を決定し、プラス共有ロックの数よりも解放され、状態を更新しようとすると、成功した場合、関連するデータの変更を開始し、3、もし同期のfirstReaderはNULLに等しいか、または現在のスレッドに等しい場合は、最初の読み取りロックの同期でのロックと追加されたロックの数を示すために、firstReaderとfirstReaderHoldCountを変更し、4、firstReaderは、他のスレッドがある場合は、ローカルスレッドのHoldCounterを取得するために共有ロックを追加する回数を保存するために使用されます。共有ロック。

tryReleaseShared(int未使用):共有ロックを解放するには、共有ロックの実装をまっすぐにする場合は、ロックを解放することは簡単です、1、firstReaderが現在のスレッドである場合、firstReaderHoldCountが1に等しい場合は、nullにfirstReader、それ以外の場合firstReaderHoldCountが減少している、2、firstReaderは、現在のスレッドではない場合、ロックが追加された回数を更新するためにローカルスレッドのHoldCounterを取得し、ロックがHoldCounterを削除するには、ローカルスレッドから最後の1つに追加された回数の場合は同じです。

要約

ReentrantReadWriteLockのSyncは、AQSの最も完全で複雑な実装であり、AQSが実装する必要がある4つのメソッドを実装しています。これらの4つのメソッドは、読み取りと書き込みロックに対応し、状態を管理するためにロックを解除し、スレッドのブロックとウェイクアップを管理するためにAQSテンプレートメソッドを使用しています。

読み取りと書き込み2つの兆候を学ぶ価値が実装上のintの状態を使用して同期。ローカルスレッドの使用は、それぞれのスレッドに加えて、読み取りロックの回数を節約するためにも、スレッドの安全性を確保します。そのような関数とほとんど、詳細に入ることはありません公正不公正なロックの数があります。

Javaプログラマの日々の勉強ノート、誤解などの交換議論を歓迎します!

Read next

ビューレイアウト

LayoutParamsとして翻訳すると、子Viewは、親コンテナの対応するものを使用して、それ自身の配置方法を親コンテナに伝えます。そのため、基本的には、各ViewGroupは、レイアウトルールをサポートするために対応するものを持っています。

Jun 22, 2020 · 5 min read