CASのスピンロック

スピンロックとは何ですか

ロック、その限られた資源のため、一部の環境では、マルチプロセッサシステムに、開始するには、複数のスレッドからのスピンロックの下メカニズム、そして時には排他的アクセス(必要相互排他)を、その後、ロックメカニズムが導入され、唯一のロックを取得プロセスは、リソースへのアクセスを得ることができます。それは1つしかないことができますし、クリティカルセクションを終了するときに一つだけのプロセスは、ロックが解除された二つ以上のプロセスがクリティカルセクションに入ることができないと同時に、自分のクリティカルセクションを入力してロックを獲得することができます。

相互排除アルゴリズムの設計、プロセスがどのように行うことではないロックを取得する際に、常に状況に直面するだろうか?

通常あり、治療の2種類が:

一つは、この問題をこの資料の焦点である、ロックを取得しない呼び出し側がスピンサイクルロックホルダがロックをリリースしているかどうかを確認することであったであるスピンロック- 。彼は都市ライン(非ブロッキング)を詰まらせることはありません。

もう一つは、ブロッキングのロックを取得していないプロセスである(内蔵のロックが同期ReentrantLockのなどを含む)ミューテックス-独自の(ブロッキング)を、あるスレッド、上の他のタスクを実行し続けます。

CAS

CAS(比較とスワップ)、つまり、比較交換するだけでなく、動作して楽観的スピンロックまたはロック私たちは通常、コア達成します。

これを達成するのは非常に簡単です、二つの値が等しい場合、それはメモリの値が期待値に置き換えると返します、期待値とメモリ値と比較することで、真。それ以外の場合はfalseを返します。

それを確保するためのアトミック操作

技術の任意の出現は、特定の問題を解決することでした、解決すべき問題は、それがアトミック操作をCAS確保することです。アトミック何の操作最小の原子が分割されていない、操作が完了する知っている、中断することができない、という操作は、一度開始し、最小のアトミック操作は、操作を分割することはできませんです。マルチスレッド環境では、原子操作はスレッドセーフ確保するための重要な手段です。例えば、仕事で2つのスレッドがあるとし、値のインクリメント演算子に変更を加えるたいインスタンスを見てみましょう、あなたは私がインクリメント整数になりたい、次の3つの基本的な手順が必要になります。

図1は、私の現在の値を読み出します。

図2に示すように、iの値がインクリメントされます。

図3に示すように、I値をメモリに書き戻されます。

2つのプロセスが読んでいると仮定し、iの現在値が、仮定はこの時間iが1、B 1スレッドを追加スレッドも、最終的に、私は1ではなく2であり、追加、0です。アトミックインクリメント動作が乱れることができる3つのステップに分割されていないためです。私は事業++を次の例として、10件のスレッド、各スレッドが実行万、我々は値が100,000で期待が、残念ながら、結果は常に10万未満です。

静的 int型私= 0 ;
パブリック 静的 ボイドアドオン(){
I ++ ;
}
 
プライベート 静的 クラス Plusは、実装{Runnableを
@オーバーライド
公共 ボイドラン(){
 int型、K <10000; K = 0 ++ kは){
追加();
}
}
}
 
パブリック 静的 ボイドメイン(文字列[]引数)がスローInterruptedExceptionあるが{
[]のスレッドスレッド = 新しいスレッド[10 ]。
以下のためにint型、iは10 <; I = 0 iは++ ){
スレッド[i]は = 新しいスレッド(新しいプラス());
スレッド[I] .start();
}
以下のためにint型、iは10 <; I = 0 iは++ ){
スレッド[I] .join()。
}
System.out.println(I);
}

もしそうなら、どのように行います。はい、あなたは、考えている可能性がロックすることができるか、利用する達成するために、同期、例えば、add()メソッドはとても以下のように変更します:

公共 同期 静的 ボイドアドオン(){
 I ++ ;
 }

あるいは、ロック動作、例えば、次の使用 ReentrantLockの(リエントラントロック)実装。

プライベート 静的ロックロック= 新しいReentrantLockの();
 パブリック 静的 ボイドアドオン(){
 lock.lock();
 I ++ ;
 施錠開錠();
 }

CASは、スピンロックを達成します

ロックやので、 synchronizedキーワードは、アトミック操作を実現するため、ロックまたはsynchronizedキーワードのパフォーマンスが大きな損失をもたらしたので、なぜ、CASを使用していますが、CAS楽観的ロックを達成することができて、それが実際に直接使用されることができますCPUの命令レベル、非常に高いパフォーマンス。

、上記の言った訳語が大人で、文字通りの意味は、彼が回転することを非常に明確であることがわかり、CASは、CASは、それが回転するように、ロックの効果を達成するために、というアトミック操作を保証するために、CPUの命令を使用して、スピンロックの基礎となっていますサイクルは、一般的に無限ループを実現するために使用されます。操作が成功した場合にこのようにして、無限ループは、CAS動作を行う、サイクルの終わり、trueを返し、それがfalseを返す場合、実行サイクルは、CAS操作は、それがtrueを返すまで試みるし続けます。

実際には、 JDKは、多くの場所で、特に、そのようなたCountDownLatch、セマフォ、ReentrantLockのようjava.util.concurrentのパッケージで、CASを使用しており、そのようなは、java.util.concurrent.atomicパッケージの下に、私たちはすべてのアトミック*前に使用信じる、などその上AtomicBoolean、のAtomicIntegerと。

ここで取ることは十分に簡単ですのでAtomicBooleanは、あなたの例を与えます。

パブリック クラス AtomicBooleanを実装したjava.io.Serializable {
  プライベート 静的 最終 長い serialVersionUIDの= 4654671469794556979Lを。
 // セットアップが更新にUnsafe.compareAndSwapIntを使用する
 プライベート 静的 最終安全でない危険な= (Unsafe.getUnsafe)。
 プライベート 静的 最終 長いvalueOffset。
 静的{
  試み{
 valueOffset = unsafe.objectFieldOffset
 (AtomicBoolean クラス .getDeclaredField( "値" ));
 } キャッチ(例外例){ スロー 新しいエラー(EX); }
 }
 プライベート 揮発 int型の値。
  
 公共の 最終 ブールのget(){
  戻り値= 0!;
 }
 パブリック 最終 ブールのcompareAndSet(ブール期待ブール更新){
  int型 E =期待?1:0 。
 int型、U =更新?1:0 。
 返す unsafe.compareAndSwapInt(これ、valueOffset、E、U)を、
 }
}

これは、コードAtomicBooleanの一部、我々は別のキーいくつかのメソッドとプロパティがあることがわかります。

図1は、sun.misc.Unsafeオブジェクトクラスを使用して、開発者は推奨されない使用、JDK内を除いて、ダイレクト・メモリ・オブジェクトの一連の動作方法を提供します。

2は、値が実際の値を示し、あなたが得る方法が実際の値に基づいて見ることができることは、揮発性メモリがあれば値の変化は、他のスレッドを発生するように値である視認性を確実にするため、値は揮発性として定義されるブール値、かどうかを決定するために0に等しいです。すぐに変更の値を参照してくださいされ、次はについて話します揮発性の可視性の問題、歓迎の注意を

図3は、valueOffsetメモリオフセット値は、後者の方法でのcompareAndSetとして使用さunsafe.objectFieldOffset方法により得られる値です。

図4に示すように、この方法を使用してCAS方法を達成することであるコアうちのcompareAndSetの方法は、唯一の所望の値に値を渡すために、更新する必要があり、その中unsafe.compareAndSwapInt(この、valueOffset、E、Uを呼び出しAtomicBoolean )ネイティブメソッドである方法は、C ++リアライズを使用して、特定のコードが投稿されていない、要するに、CMPXCHGのCPU命令の使用は、比較および交換を完了している、もちろん、システムの特定のバージョンに依存して、異なるにも実装する、関心関連する記事について検索して自由に。

利用シナリオ

  • このようなように、ブール、整数値と簡単なオブジェクトのためのCAS。
  • 同時にスピンであまりにも多くのスレッドが、そう長く循環が重要なCPUのオーバーヘッドを引き起こす可能性があればCASは、あまり競合し合います。

例えば AtomicBooleanは、このようなシナリオで使用することができ、システムは、ブール変数の属性の状態を決定する必要がマルチスレッド環境場合に繰り返し実行、AtomicBoolean、擬似コードを用いて実現することができる回避するために、初期化する必要があります次のように:

民間 最終 静的 AtomicBooleanフラグ= 新しいAtomicBoolean()。
 もし(flag.compareAndSet()){
 初期化();
 }

例えばのAtomicIntegerは、正確な計数を確実にするために、カウンタ、マルチスレッド環境で使用することができます。

ABAの問題

そこに問題CASは、あるBへの値であり、Bから、この場合、CASはあまり変化しなかったと思うし、Aに戻って変更しましたが、実際には変化があります。この点において、契約の下でAtomicStampedReferenceは、判決のバージョン番号の実現を提供していない、問題の一部を解決することができます。

より多くの学習教材について、あなたは次のFanger魏コードをスキャンすることができます

おすすめ

転載: www.cnblogs.com/lemonrel/p/11693255.html