アトミック操作:507383170を分割(中断)または一連の動作の原子動作と呼ばれることができません。
アトミックアトミックオペレーション12の主なカテゴリー、アトミック更新モードの四種類、原子の基本的なタイプ、アトミック更新アレイ、フィールドの更新原子、アトミック更新基準を更新します。アトミックパッケージラッパークラスは、基本的に危険が実装に使用されます。
基本タイプ:のAtomicInteger、AtomicLong、AtomicBoolean。
リファレンスタイプ:AtomicReference、AtomicReference、AtomicStampedRerence、AtomicMarkableReferenceのABA例。
配列型:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray。
原子修飾子(アップデータ)の属性:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater。
図1に示すように、基本的なアトミック更新型クラス
ここでは、各タイプの例を見て:
/ ** * <P>タイトル:AtomicIntegerTest.java </ P> * <P>説明:</ P> * <P>著作権:NTTデータシナジーすべての権利を保有。</ P> * <P>会社:WWW .synesoft.com.cn </ P> * <P> @datetime 2019年8月9日上午8時01分30秒</ P> * <P> $リビジョン$ </ P> * <P> $日付$ </ P> * <P> $ Idを$ </ P> * / パッケージcom.test。 輸入java.util.concurrent.atomic.AtomicInteger。 / ** * @authorのhong_liping * * / publicクラスAtomicIntegerTest { 静的のAtomicInteger AI =新規のAtomicInteger()。 公共の静的な無効メイン(文字列[]引数)が{ ため(INT i = 0; iが10 <。 @Override ます。public void RUN(){ ai.incrementAndGet(); } })スタート(); } //試し{ //のThread.sleep(100); //}キャッチ(InterruptedExceptionあるE){ // e.printStackTrace (); //} のSystem.out.println( "次のサイクルの結果:" + ai.get()); } }
//テスト結果
:9次のように回転結果は
以下のようにサイクル後の結果であった:10
コード9は、なぜ、スレッドが終了していないので、私が持っていた以下のプレイアウト、聞かせて糸の睡眠ではない10 10でありながら、上記のコードによると、私たちは数回以上実行、あなたは一瞬のためのテスト結果を検索します私たちは、この問題を解決することができます。
ここでは、原子ABAの問題を見て、面接時の問題が頻繁に尋ねました。
/ ** * <P>タイトル:AtomicTest.java </ P> * <P>説明:</ P> * <P> @datetime 2019年8月8日下午午前3時40分37秒</ P> * < P> $リビジョン$ </ P> * <P> $日付$ </ P> * <P> $ Idを$ </ P> * / パッケージcom.test。 輸入java.util.concurrent.atomic.AtomicInteger。 / ** * @author hong_liping * * / publicクラスAtomicAbaTest { 新しい= ATOのAtomicInteger(1)のAtomicIntegerプライベート静的。 パブリック静的無効メイン(文字列[] args){ スレッドのmaint =新しいスレッド(新しいRunnableを(){ @Override 公共ボイドラン(){ int型A = ato.get()。 System.out.println(にThread.currentThread()のgetName()+ "原子操作修改前数据" + A)。 {試みる のThread.sleep(200)。 }キャッチ(InterruptedExceptionある電子){ e.printStackTrace(); } ブールsuccessFlag = ato.compareAndSet(2)。 (successFlag){場合 のSystem.out.println(にThread.currentThread()のgetName()+ "原子操作修改后数据" + ato.get())。 } } }、 "MAINT")。 スレッドotherT =新しいスレッド(新しいRunnableを(){ @Override ます。public void実行(){ int型、B = ato.incrementAndGet(); System.out.println(にThread.currentThread()のgetName( )+ " のB +データの後にアトミックインクリメント動作"); B = ato.decrementAndGet(); // 2-1 するSystem.out.println(にThread.currentThread ().getName()+)のB + "データので、アトミック操作を保存"; } }、 "OtherT"); mainT.start(); otherT.start(); } }
テスト結果:
OtherT 2原子増分データの後の
修正データ前MAINTアトミック操作1つの
後OtherT原子デクリメントデータ
データMAINT 2を変更するためのポストアトミック操作
上記の動作によれば、我々はその操作のAtomicIntegerインクリメント、デクリメントなど別の方法として値を見ることができます。完了MAINT 2(代替2)の後に実行値、otherT 2-1実行2(1 + 1にインクリメントされる:ここで、問題アトミック操作ABAがあることに留意すべきである、ABA問題は現象をすることです)結果。2が同じ2、抜け穴の同等の、あなたがに投資する王健林から千万アカウントを盗んだというのは同じではありませんこれら二つのスレッドで使用されるので、あなたがより良いバックこの投資して、あなたをこの千万ダースはバック王健林アカウントに、この全体のプロセスは、あなたは自分のお金を失った、またはそこに入れていなかった王健林、のためので、全体の動作を記録していなかった、王健林を見つけられませんでした。それがこの問題を解決する最良の方法は、ABAであることは明らかである場合には、操作のすべてのステップは、あなたがお金を盗むように1があり、全体のプロセスのうちの、ちょうど見て、王健林をお金を返済、マーク、水の銀行と同等のものを作ることです私は合計金が変更されていないことがわかりますが、運転記録は、私のお金は人によって盗まれ、その後アップ戻って来ていたことを示しています。それはどこAtomicStampeReferenceです。
2、参照型アトミック更新
次はAtomicStampedReferenceのテストクラスを見てみましょう。
/ ** * <P>タイトル:AtomicStampedReference.java </ P> * <P>説明:</ P> * <P> @datetime 2019年8月9日上午8時35分56秒</ P> * < P> $リビジョン$ </ P> * <P> $日付$ </ P> * <P> $ Idを$ </ P> * / パッケージcom.test。 輸入java.util.concurrent.atomic.AtomicInteger。 輸入java.util.concurrent.atomic.AtomicStampedReference。 / ** * @author hong_liping * * / publicクラスAtomicStampedReferenceTest { プライベート静的AtomicStampedReference <整数> ASF =新しいAtomicStampedReference <整数>(1、0); RUNボイドパブリック(){ int型= asf.getStampスタンプ(); 。のSystem.out.println(にThread.currentThread()のgetName()+ "アトミックデータ変更前" asf.getReference +()+ "_" +スタンプ); 試み{ のThread.sleep(1000); }キャッチ(InterruptedExceptionあるE){ e.printStackTrace()は; } //この時点でexpectedReference変化していないが、スタンプは、CAS障害ので、改変された ブールsuccessFlag = asf.compareAndSet (1、2、スタンプ、スタンプ+ 1); IF(successFlag){ 。のSystem.out.println(にThread.currentThread()のgetName()+ "アトミック修正されたデータ" + asf.getReference()+ "_" +スタンプ)。 } {他 asf.compareAndSet(2、1、スタンプ、スタンプ+ 1)。 System.out.println(にThread.currentThread()のgetName()+ "CAS操作失败"); } } }、 "MAINT")。 スレッドotherT =新しいスレッド(新しいRunnableを(){ @Override ます。public void実行(){ int型のスタンプ= asf.getStamp(); asf.compareAndSet(1、2、スタンプ、スタンプ+ 1); System.out.printlnは(スレッド。.currentThread()のgetName()+ "原子操作自增后数据" + asf.getReference()+ "_" + asf.getReference()) 。のSystem.out.println(にThread.currentThread()のgetName() + "原子操作自减后数据" + asf.getReference()+ "_" +スタンプ);; }、 "OtherT"); mainT.start(); otherT.start()。 } } //テスト結果: MAINTアトミック操作変更データの前2_0 データの後OtherTアトミックインクリメント操作2_2 2_0原子からのデータを保存OtherT mainTcas操作に失敗しました
次はAtomicIntegerArrayのケースを見て
/ ** * <P>タイトル:AtomicArrayTest.java </ P> * <P>説明:</ P> * <P> @datetime 2019年8月10日上午9時45分49秒</ P> * < P> $リビジョン$ </ P> * <P> $日付$ </ P> * <P> $ Idを$ </ P> * / パッケージcom.test。 輸入java.util.concurrent.atomic.AtomicIntegerArray; 輸入com.sun.org.apache.bcel.internal.generic.NEWARRAY; / ** * @author hong_liping * * / publicクラスAtomicArrayTest { 静的INT []配列=新しいINT [] {1,2,3}。 静的AtomicIntegerArrayのAIA =新しいAtomicIntegerArray(配列)。 パブリック静的無効メイン(文字列[] args){ aia.getAndSet(1,5)。 IF(aia.get(1)==アレイ。[1]){ するSystem.out.println( "アレイにおける原子配列の値が等しい"); }そう{ のSystem.out.println(「アレイにおける原子配列の値が等しくない」); } } }
結果:
。5
2
における配列原子のアレイ内の値に等しくありません
コードは、私がデータ自体を定義し、同じ値のインデックスを持つ上記の原子の配列が同じではありません、そして、なぜ、我々はデータソースを見てあなたは、私は変数自体を定義アトミックでない操作を見つけるだろう、から見ることができますこれは、最初のコピーで、その後の操作は、コピーバージョンです。
AtomicIntegerArrayパブリック([]配列をINT){ //最後のフィールドによって保証可視性が保証 this.array array.clone =を(); //配列の初期化時コピー }
公共最終INT getAndSet(INT I、INT newValueに){ 戻りunsafe.getAndSetInt(アレイ、checkedByteOffset(I)、newValueに)。 }
安全でないデータ型の魔法を実行するときにアトミック操作を使用しました。
4、アトミック更新フィールドクラス
次はAtomicIngerFieldUpdaterを見て
/ ** * <P>タイトル:AtomicIntegerFieldUpdateTest.java </ P> * <P>説明:</ P> * <P> @datetime 2019年8月10日上午10時02分22秒</ P> * < P> $リビジョン$ </ P> * <P> $日付$ </ P> * <P> $ Idを$ </ P> * / パッケージcom.test。 輸入java.util.concurrent.atomic.AtomicIntegerFieldUpdater。 / ** * @author hong_liping * * / publicクラスAtomicIntegerFieldUpdateTest { 静的AtomicIntegerFieldUpdaterアイフ= AtomicIntegerFieldUpdater.newUpdater(Person.class、 "年齢"); 静的クラスPerson { プライベート文字列名; 公共の揮発性のint型の年齢; this.name =名前; this.age =年齢; } 公共INT getAge(){ 戻り年齢;