ReentrantLockの公平ロックと不公平ロックの違いについての話

序文

最近、Java Concurrent Programmingという本を読み、ReentrantLockのソースコードを読みました。以前、インタビュアーから、公平なロックと不公平なロックの違いは何ですかと質問されました。ソースコードレベルでの違いについて話したばかりです。ですが、パフォーマンスの点で違いもあります。今日はそれについて話しましょう。

公平と不公平

ReentrantLockコンストラクターには2 つのオプションがあり、デフォルトで不公平なロックを作成するか、公平なロックを作成するように指定します。
公平なロックでは、スレッドは要求した順序でロックを取得します。別のスレッドがロックを保持している場合、または他のスレッドがキュー内でロックを待機している場合は、新しく要求したスレッドがキューに配置されます。
不公平なロックでは、「キュー ジャンプ」が許可されます: スレッドが不当なロックを要求するとき、要求の発行時にロックの状態が利用可能になると、スレッドはキュー内で待機しているすべてのスレッドをスキップし、ロックを直接取得します。 。ロックがスレッドによって保持されている場合にのみ、新しく要求したスレッドがキューに入れられます。

公平または不公平なロックを選択する方法

なぜ公平と不公平の間に区別があるのでしょうか? 公平な世界とは安定した温かい世界であり、不公平なことは悪いことであると誰もが一般的に信じていますが、ロックの世界ではどうでしょうか。
公平性は、ロック操作の実行時にスレッドを一時停止および再開するオーバーヘッドにより、パフォーマンスを大幅に低下させる可能性があります。実際のほとんどの場合、不公平なロックのパフォーマンスは公正なロックのパフォーマンスよりもはるかに高くなります。

次の図は、Map のパフォーマンス テストを示し、公平なパッケージ化と不公平なパッケージングによる HashMap のパフォーマンスを比較していますReentrantLock。この図から、公平性によってパフォーマンスが約 2 桁低下することがわかります。
ここに画像の説明を挿入

備考:ConcurrentHashMapスレッド数が 4 から 8 の間では多少の変動があります。この変動は測定ノイズに属します。この種のノイズはパフォーマンス テストでよく見られます。全体の結果には大きな影響を与えないため、使用しないでください。それに過度に注意を払います。

上の図からわかるように、激しい競争下では、不公平なロックのパフォーマンスが公平なロックよりもはるかに高くなりますが、その理由は、中断されたスレッドが再開されてから実際に実行が開始されるまでに大幅な遅延が生じるためです。

  • スレッド A がロックを保持し、スレッド B がロックを要求するとします。
  • このロックはすでにスレッド A によって保持されているため、スレッド B はキューに入れられ、一時停止されます。
  • A がロックを解放すると、B がウェイクアップされるため、再度ロックを取得しようとします。
  • 同時に、ロックを要求している C スレッドがたまたま存在するため、B が完全に目覚める前に、C スレッドがロックを取得、使用、解放する可能性があります。
  • C スレッドが使用を終了して解放した後、B スレッドが起動し、ロックを取得して使用します。

これにより、スレッド B がロックを取得する時間が遅れることがなくなり、B が起きたときに C もニュートラル位置で作業を終了するため、最終的なスループットも向上します。

それでは、どのような場合に公平なロックを使用するのでしょうか?
公平なロックは、ロックが比較的長期間保持される場合、またはロックを要求する間の平均時間間隔が長い場合に使用する必要があります。この場合、「キュージャンプ」(ロックが利用可能な場合、スレッドはまだ起動中である) によってもたらされるスループットの向上が現れない可能性があります。

ReentrantLock内蔵ロック付き

ロックに関して言えば、私たちが最もよく知っている組み込みロックについて言及する必要があります。Sychronizedでは、これら 2 つのロックをどのように選択すればよいでしょうか?
ReentrantLock組み込みロックと比較して、時限ロック待機、割り込み可能なロック待機、公平性、および非ブロック構造を実装するシャックルも含まれます。そのパフォーマンスは組み込みロックよりも優れているようで、Java6 ではわずかに優れていますが、Java5 でははるかに優れています。それなら、内蔵ロックを放棄して直接選択してみてはいかがでしょうかReentrantLock?
理由は次のとおりです

  • ReentrantLock組み込みのロックよりも危険性が高く、finally ブロックでunlockメソッドを呼び出すのを忘れた場合、表面上はコードが正常に実行できても、時限爆弾を埋めたようなものとなり、罪のない人に被害を与える可能性があります。
  • また、スレッドダンプではどの呼び出しフレームでロックが取得され、デッドロックしたスレッドを検出・特定できるという利点もありますSychronizedReentrantLockJava6 では、管理およびデバッグ インターフェイスも提供されており、このインターフェイスを通じてロックを登録できるため、関連するロック情報の一部がスレッド ダンプに表示され、プログラマに役立ちます。ReentrantLock非ブロック構造機能を使用してロックを取得する操作は、特定のスタック フレームに関連付けることはできませんが、組み込みロックでは関連付けることができます。
  • Sychronized将来的にはパフォーマンスが向上する可能性が高くなりますReentrantLockSychronizedこれは JVM の組み込みプロパティであるため、スレッドで囲まれたロック オブジェクトのロック削除の最適化や、Java6 以降のロック エスカレーションの最適化など、いくつかの最適化を実行できます

では、いつ選択すればよいのでしょうかReentrantLock?
一部の組み込みロックではニーズを満たせない場合に、ReentrantLock高度なツールとして使用できます。これは、時間指定、ポーリング可能および割り込み可能なロック取得操作、均等なキュー、非ブロック構造のロックなどの高度な機能が必要な場合にのみ使用してくださいReentrantLockそれ以外の場合は、引き続き組み込みロックを最初に使用する必要がありますSychronized

----------知れば知るほど、知らないことが増える----------

おすすめ

転載: blog.csdn.net/fhf2424045058/article/details/128394735