記事では、インタビューに必要な楽観的および悲観的なロックを学ぶことができます

ここに写真の説明を挿入

悲観的ロックと楽観的ロックとは何ですか

楽観的なロックは、物事が良くなることを常に考えている人生の楽観的な人々に対応し、悲観的なロックは、物事が悪くなることを常に考えている人生の悲観的な人々に対応します。この2種類の人にはそれぞれ長所と短所があり、シーンによっては一方が他方よりも優れています。

悲観的なロック

常に最悪のケースを想定します。データを取得するたびに、他の人がデータを変更すると思うので、データを取得するたびにロックして、データを取得したい他の人がロックを取得するまでブロックするようにします(共有リソース一度に1つのスレッドでのみ使用され、他のスレッドはブロックされ、リソースは使用後に他のスレッドに転送されます)。このようなロックメカニズムの多くは、行ロック、テーブルロックなど、読み取りロック、書き込みロックなど、操作前にすべてロックされる従来のリレーショナルデータベースで使用されます。JavaのsynchronizedやReentrantLockなどの排他的ロックは、悲観的なロックのアイデアを実現したものです。

楽観的なロック

常に最善の状況を想定します。データを取得するたびに、他の人がデータを変更しないと思うので、ロックされませんが、更新時に、この期間中に他の人がデータを更新したかどうかが判断されます。バージョンを使用できます。番号メカニズムとCASアルゴリズムの実装。オプティミスティックロックは、スループットを向上させることができるマルチリードアプリケーションタイプに適しています。データベースによって提供されるwrite_conditionと同様のメカニズムは、実際にはオプティミスティックロックです。Javaのjava.util.concurrent.atomicパッケージのアトミック変数クラスは、楽観的ロックの実装であるCASを使用して実装されます。

主要な工場からのドキュメントやより実際のインタビューの質問を整理するためのさまざまなナレッジポイントモジュールもあります。困っている友達は、以下のリンクをクリックして無料で入手できます。

リンク:1103806531パスワード:CSDN

ここに写真の説明を挿入

2つのロックのシナリオを使用する

上記の2つのロックの導入から、2つのロックにはそれぞれ長所と短所があることがわかります。一方を他方よりも優れていると見なすべきではありません。たとえば、楽観的ロックは書き込みを少なくする(より多くのシナリオを読む)のに適しています。つまり、競合は真です。これがめったに発生しない場合、これによりロックのオーバーヘッドが節約され、システムの全体的なスループットが向上します。ただし、上書きすると、通常、競合が頻繁に発生し、上位アプリケーションが常に再試行されてパフォーマンスが低下するため、上書きのシナリオではペシミスティックロックを使用する方が適切です。

楽観的ロックの2つの一般的な実装

楽観的ロックは通常、バージョン番号メカニズムまたはCASアルゴリズムを使用して実装されます。

1.バージョン番号メカニズム

通常、データのバージョン番号バージョンフィールドは、データが変更された回数を示すためにデータテーブルに追加されます。データが変更されると、バージョン値が1つ増加します。スレッドAがデータ値を更新する場合、データの読み取り中にバージョン値も読み取ります。更新を送信するときに、今読み取ったバージョン値が現在のデータベースのバージョン値と等しい場合は更新します。それ以外の場合は再試行します。更新が成功するまで操作を更新します。

簡単な例を挙げてください。

データベースのアカウント情報テーブルにバージョンフィールドがあるとすると、現在の値は1であり、現在のアカウント残高フィールド(残高)は$ 100です。

オペレーターAはそれを読み取り(バージョン= 1)、アカウント残高から$ 50($ 100- $ 50)を差し引きます。
オペレーターAの操作中に、オペレーターBもこのユーザー情報(バージョン= 1)を読み取り、アカウント残高から$ 20($ 100- $ 20)を差し引きます。
オペレーターAは変更作業を完了し、データバージョン番号に1を追加し(バージョン= 2)、アカウント控除残高(残高= $ 50)とともに更新のためにデータベースに送信します。この時点で、送信されたデータバージョンはデータベースレコードの現在のバージョンよりも大きいため、データは更新、データベースレコードのバージョンが2に更新されます。
オペレーターBは操作を完了し、バージョン番号も1つ増やし(version = 2)、データベースにデータを送信しようとしました(balance = $ 80)が、このとき、データベースレコードのバージョンを比較すると、オペレーターBが送信したデータバージョン番号は2であることがわかりました。 、データベースレコードの現在のバージョンも2であり、「更新を実行するには、送信されたバージョンがレコードの現在のバージョンよりも大きくなければならない」という楽観的なロック戦略を満たしていないため、演算子Bの送信は拒否されます。

このようにして、オペレーターBがオペレーターAの操作結果をバージョン= 1に基づく古いデータ変更の結果で上書きすることが回避されます。

2.CASアルゴリズム

つまり、比較とスワップ(比較とスワップ)は、よく知られているロックフリーアルゴリズムです。ロックフリープログラミング、つまり、ロックを使用せずに複数のスレッド間で可変同期を実現する、つまり、スレッドをブロックせずに可変同期を実現するため、非ブロッキング同期(非ブロッキング同期)とも呼ばれます。

CASアルゴリズムには3つのオペランドが含まれます

  • メモリ値Vの読み取りと書き込みが必要
  • 比較する値A
  • 書き込まれる新しい値B

Vの値がAに等しい場合にのみ、CASはVの値を新しい値Bでアトミックに更新します。それ以外の場合、操作は実行されません(比較と置換はアトミック操作です)。通常の状況では、これはスピン操作、つまり一定の再試行です。

楽観的ロックのデメリット

ABAの問題は、楽観的なロックに関する一般的な問題です。

1ABAの問題

変数Vが最初に読み取られたときのAの値であり、割り当てる準備ができたときにまだAの値であることが確認された場合、その値が他のスレッドによって変更されていないことを示すことができますか?この間に値が別の値に変更されてからAに戻される可能性があるため、明らかにできません。CAS操作では、変更されたことがないと誤って信じてしまいます。この問題は、CAS運用の「ABA」問題と呼ばれます。

JDK 1.5以降のAtomicStampedReferenceクラスは、この機能を提供します。compareAndSetメソッドは、最初に、現在の参照が期待される参照と等しいかどうか、および現在のフラグが期待されるフラグと等しいかどうかを確認します。すべてが等しい場合、参照とフラグはアトミックになります。値は指定された更新値に設定されます。

2長いサイクルタイムと高いオーバーヘッド

スピンCAS(つまり、成功するまでループで実行されます)が長時間失敗すると、CPUに非常に大きな実行オーバーヘッドが発生します。JVMがプロセッサによって提供される一時停止命令をサポートできる場合、効率が向上します。一時停止命令には2つの機能があります。1つは、CPUが実行リソースを過度に消費しないように、命令のパイプライン解除実行を遅らせることができます。遅延時間は特定の実装バージョンによって異なり、一部のプロセッサでは遅延時間はゼロです。第2に、ループを終了するときのメモリ順序違反によって引き起こされるCPUパイプラインのフラッシュを回避できるため、CPUの実行効率が向上します。

3は共有変数のアトミック操作のみを保証できます

CASは、単一の共有変数に対してのみ有効です。操作に複数の共有変数が含まれる場合、CASは無効です。ただし、JDK 1.5以降、参照オブジェクト間の原子性を確保するためにAtomicReferenceクラスが提供されています。CAS操作用に1つのオブジェクトに複数の変数を配置できるため、ロックを使用するか、AtomicReferenceクラスを使用して複数の共有変数を共有できます。共有変数にマージして操作します。

CASと同期のシナリオを使用する

簡単に言えば、CASは書き込みが少ない(読み取りシナリオが多い、一般に競合が少ない)のに適しており、同期は書き込みが多い(書き込みシナリオが多い、一般に競合が多い)のに適しています。

リソースの競合が少ない(スレッドの競合が少ない)場合、スレッドのブロックとウェイクアップの切り替え、およびユーザーモードとカーネルモード間の切り替え操作に同期同期ロックを使用すると、cpuリソースが浪費されます。CASはハードウェアに基づいており、カーネルに入る必要はありません。スレッドを切り替える必要がなく、スピンを操作する可能性が少ないため、より高いパフォーマンスを得ることができます。
深刻なリソース競合(深刻なスレッド競合)の場合、CASスピンの可能性は比較的高く、これはより多くのCPUリソースを浪費し、同期よりも効率が低くなります。

補足:Javaコンカレントプログラミングの分野で同期されたキーワードは常にベテランの役割でした。昔、多くの人がそれを「ヘビーウェイトロック」と呼んでいました。ただし、JavaSE 1.6以降は、ロックの取得と解放のパフォーマンス消費を削減するために主に含まれ、バイアスロックや軽量ロックの導入、およびその他のさまざまな最適化の重要性が低くなる場合があります。 。同期の基本的な実装は、主にロックフリーキューに依存しています。基本的な考え方は、スピン後にブロックし、競合する切り替え後もロックを競い続けることです。これにより、公平性がわずかに犠牲になりますが、高いスループットが実現します。スレッドの競合が少ない場合は、CASと同様のパフォーマンスが得られます。深刻なスレッドの競合の場合は、CASよりもパフォーマンスがはるかに高くなります。

総括する

時間の制約により、詳細は記載されていません。フルバージョンが必要な友達は、以下のリンクをクリックして無料で入手できます。

リンク:1103806531パスワード:CSDN

ここに写真の説明を挿入
ここに写真の説明を挿入

おすすめ

転載: blog.csdn.net/weixin_48655626/article/details/109097217