提起1.問題
クラスのメンバ変数のプロパティとのAtomicIntegerの下で見て:
// 更新にUnsafe.compareAndSwapIntを使用するように設定 プライベート 静的 最終安全でない危険な= Unsafe.getUnsafe(); プライベート 静的 最終 長いvalueOffset。 静的{ 試み{ valueOffset = unsafe.objectFieldOffset (のAtomicInteger。クラス .getDeclaredField( "値" )); } キャッチ(例外例){ スロー 新しいエラー(EX); } } プライベート 揮発 int型の値。
あなたは見ることができます:
1.AtomicIntegerクラスは、アトミック性を確保するために安全でない、ダイレクトメモリ操作を使用しています。
2. valueOffsetのロングタイプがあります。ときにクラスがロードされ、値が初期化されます。
3.揮発性の修正値を持つint型のメンバー変数を有します。
値我々が得ることを、明らかに価値のAtomicIntegerパッケージ値である、これを参照してください。しかし、それvalueOffset値が何を表すかありますか?そして、これはどのように危険な操作ですか?
2.valueOffset
方法初期化彼らの割り当てを参照してください、それは危険なメソッドのネイティブは、次のとおりです。
公共 ネイティブ 長い objectFieldOffset(フィールドVAR1)。
objectFieldOffset方法は、(百度から)オフセットオブジェクトのメモリアドレスに対するメモリメンバプロパティのアドレスを返します
次に各オブジェクトに対して、オフセットは、クラス変数として、固定されています。
そして、メモリアドレス+オフセットオブジェクトは、メモリ内のメンバ変数の値の特定のアドレスを知ることができ、そして今回は、それを操作することができ、かつ「安全」から今回のJavaは、「安全でない」こと。
危険なに関しては3
それは私たちが、使用方法によってのAtomicIntegerを見て、メモリベースの直接操作のために安全ではありません。
、インクリメントデクリメント典型的な非アトミック操作がのAtomicIntegerどのように行われるかを見て。
/ ** *現在の値を1原子的に増分します。 * * @return 前回値 * / パブリック 最終 INT getAndIncrement(){ リターン unsafe.getAndAddInt(この、valueOffset、1 )。 } / ** *原子的には、現在の値を1減らします。 * * @return 前回値 * / パブリック 最終 INT getAndDecrement(){ リターン unsafe.getAndAddInt(この、valueOffset、-1 )。 }
結果を見てください:
戻り値が間違っを使用していない、古いの値であり、
これは、我々が危険な方法で見たものです。
公共 最終 INT getAndAddInt(オブジェクトVAR1、長い VAR2、int型VAR4){ int型VAR5。 実行{ VAR5 = この.getIntVolatile(VAR1、VAR2)を、 } ながら(!この .compareAndSwapInt(VAR1、VAR2、VAR5、VAR5 + VAR4))。 リターンVAR5。 }
Unsafe.getObjectVolatile():
変数の値を取得したオブジェクトを考えると、揮発性のセマンティックセマンティック負荷の使用は、実際の値は、この時間は常に値を取得することが有効であることを保証するために、CPUのキャッシュに使用されていません取得し、メインメモリからロードされます
compareAndSwapInt(VAR1、VAR2、VAR5、VAR5 + VAR4):
メモリオブジェクトVAR1に位置見つけるp
設け、VAR2オフセットバイトをp+var2
整数値にすることをy
、
場合にy ==var5
、割り当てが実行されy = var5+var4
、戻りtrue
場合はy != var5
割り当てを行わない、戻りますfalse
unsafe.getAndAddInt(オブジェクトVAR1、長いVAR2、int型のVAR4)ことを、私たちはコードを読んで:
オフセットVAR1での値にメンバ変数を取る1.値を所望の値として読み込まれた後に、形成しVAR2。
2.割り当て時に、メモリは、比較するために開始し、期待値をフェッチし、それらが等しい場合、その後、割当てを算出成功端を返します。
3.それ以外の場合は、サイクルの最初のステップ。
CASは、実際に危険な中で実現されています。
その後のAtomicIntegerの他の方法を見て
B。
/ ** *現在の値を取得します。 * * @return 現在の値 * / パブリック 最終 INT のget(){ 戻り値。 } / ** *指定された値に設定します。 * * @param newValueに新しい値 * / 公共の 最終的な ボイド集合(INT newValueに){ 値 = newValueに。 }
メンバー変数は、両方のメモリの視認性を確保するために、揮発性の修飾であるため、最も簡単な方法は、設定されます。
C。
残りのメソッドは、それらを表示されませんが、基本的な原則は)すべてunsafe.compareAndSwapInt(ある、古い格言は、原子性を確保するためにCASを使用することである総括。