Javaのロックは次のタイプに分けられます
- 楽観的ロック、悲観的ロック
- 排他ロック、共有ロック
- フェアロック、アンフェアロック
- ミューテックス、読み取り/書き込みロック
- リエントラントロック
- セグメントロック
- ロックのアップグレード(ロックなし->たわみロック->軽量ロック->重量ロック)
上記はいくつかのロック用語です。これらのカテゴリはすべてロックの状態を指すわけではありません。ロックの特性を指すものもあれば、ロックの設計を指すものもあります。以下に要約する内容は、各ロックの特定の説明です。期間。
1.楽観的ロックと悲観的ロック
楽観的ロックと悲観的ロックは、特に2種類のロックを指すのではなく、人々によって定義された概念またはアイデアであり、主に同時同期の観点を指します。
オプティミスティックロック:オプティミスティックロックは、スレッドがデータを取得するときに他のスレッドがデータを変更しないと見なすため、ロックされませんが、更新時に、他のスレッドがこの期間中にデータを更新したかどうかを判断します。
実装方法:CASメカニズム、バージョン番号メカニズム(レコードデータベースバージョン)
CASは楽観的ロック技術です。複数のスレッドがCASを使用して同じ変数を同時に更新しようとすると、1つのスレッドのみが変数の値を更新でき、他のスレッドは失敗します。失敗したスレッドは中断されませんが、中断されます。このコンテストに失敗したことを知らせて、もう一度やり直してください。
楽観的ロックを実現するためのバージョン番号メカニズム
ABA問題:
ABA問題はCASメカニズムの問題であり、彼の説明はこのようなものです。実演するために直接絵を描きます、
どういう意味ですか?つまり、スレッドはデータAをBに変更してから、再びAになります。このとき、別のスレッドがそれを読み取り、Aが変更されていないことを検出すると、元のAと間違えます。これは有名なABA問題です。ABA問題の結果は何ですか?例を挙げましょう。
誰かの家からお金を盗んで返還した泥棒。それでも元のお金ですか?浮気した後、あなたの妻は戻ってきましたか?それでも元の妻ですか?ABA問題は同じですが、適切に解決されないと、多くの問題が発生します。最も一般的な問題は資金調達です。つまり、誰かがあなたのお金を悪用した場合、あなたはそれを見つける前にそれを返済します。しかし、他の人は法律に違反しています。
解決策:タイムスタンプまたはバージョン番号を追加して、毎回バージョン番号を比較します
悲観的ロック:常に最悪のケースを想定し、データを取得するたびに他の人がそれを変更すると考えてください。したがって、データを取得するたびにロックし、他の人が取得したい場合はロックを取得するまでブロックします。データ。たとえば、Javaでの同期プリミティブのsynchronizedキーワードの実装は、悲観的なロックです。
悲観的な同時実行制御は、実際には「アクセス前にロックをフェッチする」という保守的な戦略であり、データ処理のセキュリティを保証します。
Javaでの悲観的ロックの使用は、さまざまなロックの使用です。
Javaでの楽観的ロックの使用はロックフリープログラミングであり、CASアルゴリズムがよく使用されます。典型的な例は、CASスピンを介してアトミック操作の更新を実装するアトミッククラスです。
2.排他ロック/共有ロック
2種類のロックは単なる概念です
排他的ロック:ロックは一度に1つのスレッドでのみ保持できます
共有ロック:ロックは複数のスレッドで保持できます
例えば:
Synchronizedは排他ロックです。
リエントラントロックは排他的ロックです。
ReentrantReadWriteLockの読み取りロックReadLockは共有ロックであり、書き込みロックWriteLockは排他ロックです。
排他的ロックと共有ロックはAQS(AbstractQueuedSynchronizer)によって実現され、さまざまなメソッドを実装することにより、排他的ロックまたは共有ロックを実現できます。
3.ミューテックス/読み取り/書き込みロック
上記の排他ロック/共有ロックは概念であり、相互排他ロック/読み取り/書き込みロックは具体的な実現です。
相互排他ロックの特定の実装は同期され、ReentrantLockされます。ReentrantLockはJDK1.5の新機能です。ReentrantLockを使用すると、同期された従来のロックメカニズムを完全に置き換えることができ、より柔軟になります。
読み取り/書き込みロック固有の実装は、読み取り/書き込みロックReadWriteLockです。
4.リエントラントロック
リエントラントロックは、再帰ロックとも呼ばれ、同じスレッドが外部メソッドでロックを取得すると、内部メソッドに入るときに自動的にロックを取得することを意味します。これは少し抽象的です。以下にコード例があります。
Java ReetrantLockの場合、名前から、それが再入可能ロックであり、その名前が再入可能ロックであることがわかります。
Synchronizedの場合、これは再入可能ロックでもあります。リエントラントロックの利点の1つは、デッドロックをある程度回避できることです。
synchronized void setA() throws Exception{
Thread.sleep(1000);
setB();
}
synchronized void setB() throws Exception{
Thread.sleep(1000);
}
上記のコードは、再入可能ロックの機能です。再入可能ロックでない場合、setBは現在のスレッドによって実行されない可能性があり、デッドロックが発生する可能性があります。
利点:デッドロックを回避します
5.フェアロック&アンフェアロック
公平なロックとは、複数のスレッドがロックを適用する順序でロックを取得することを意味します。
不公平なロックとは、複数のスレッドがロックを取得する順序がロックを適用する順序ではないことを意味します。後で適用するスレッドが、最初に適用するスレッドよりも最初にロックを取得する可能性があります。優先順位の逆転や飢餓を引き起こす可能性があります。
Java ReetrantLockの場合、コンストラクターはロックがフェアロックであるかどうかを指定し、デフォルトはアンフェアロックです。不公平なロックの利点は、スループットが公平なロックよりも大きいことです。
Synchronizedの場合、これは不公平なロックでもあります。AQSを介してスレッドスケジューリングを実装するReentrantLockとは異なるため、公平なロックにする方法はありません。
6.セグメント化されたロック
セグメント化されたロックは実際にはロック設計であり、特定のタイプのロックではありません。ConcurrentHashMapの場合、その同時実行性は、効率的な同時操作を実現するためにセグメント化されたロックの形式で実現されます。
ConcurrentHashMapを使用して、セグメントロックの意味と設計のアイデアについて説明しましょう。ConcurrentHashMapのセグメントロックはSegmentと呼ばれ、HashMapの構造(JDK7およびJDK8でのHashMapの実装)に似ています。内部のエントリ配列。の各要素はリンクされたリストであると同時に、ReentrantLockです(セグメントはReentrantLockを継承します)。
put要素が必要な場合は、ハッシュマップ全体をロックするのではなく、ハッシュコードを介してどのセグメントに配置するかを認識し、このセグメントをロックするため、マルチスレッドのプットの場合は、そうでない限りセグメントに配置すると、真の並列挿入が実現します。
ただし、サイズをカウントする場合、ハッシュマップのグローバル情報を取得する場合は、統計用のすべてのセグメントロックを取得する必要があります。
セグメント化されたロックの設計目的は、ロックの粒度を調整することです。操作で配列全体を更新する必要がない場合、配列内の1つのアイテムのみがロックされます。
7.バイアスロック&軽量ロック&ヘビーウェイトロック
これらの3つのロックは、ロックの状態を参照し、同期用です。Java 5では、効率的な同期を実現するためにロックエスカレーションメカニズムが導入されています。これらの3つのロックの状態は、オブジェクトモニターのオブジェクトヘッダーのフィールドによって示されます。
バイアスロックとは、同期されたコードの一部がスレッドによってアクセスされた後、スレッドが自動的にロックを取得することを意味します。ロックを取得するコストを削減します。
軽量ロックとは、ロックがバイアスされたロックの場合、別のスレッドからアクセスされ、バイアスされたロックが軽量ロックにアップグレードされ、他のスレッドがブロックせずにスピンによってロックを取得し、パフォーマンスを向上させることを意味します。
重量ロックとは、ロックが軽量ロックの場合、別のスレッドが回転していても、スピンが永久に継続しないことを意味します。スピンが一定回数の場合、ロックは取得されておらず、ブロックに入ります。ロックはヘビーウェイトロックに拡張されます。重量級のロックは、彼が申請したスレッドをブロックし、パフォーマンスを低下させます。
ロックの長所と短所の比較
ロック | 利点 | 不利益 | 該当シーン |
---|---|---|---|
バイアスロック | ロックとロック解除は追加の消費を必要とせず、非同期メソッドの実装間にはナノ秒のギャップしかありません | スレッド間でロックの競合がある場合、追加のロックキャンセルコストが発生します | 1つのスレッドのみが同期ブロックにアクセスするシナリオに適しています |
軽量ロック | 競合するスレッドがブロックされないため、プログラムの応答速度が向上します | ロック競合を取得できないスレッドがスピンを使用すると、CPUを消費します | 応答時間を追求し、ロック占有時間が非常に短い |
ヘビー級ロック | スレッドの競合はスピンを使用せず、CPUを消費しません | スレッドのブロック、応答時間が遅い | スループットを追求し、ロックに時間がかかる |
8.スピンロック
Javaでは、スピンロックは、ロックを取得しようとしているスレッドがすぐにブロックされるのではなく、ループでロックを取得しようとすることを意味します。これの利点は、スレッドコンテキストスイッチングの消費を減らすことです。欠点は、ループはCPUを消費します。