原子アトミック&安全でないの並行プログラミング動作

アトミック操作:507383170を分割(中断)または一連の動作の原子動作と呼ばれることができません。

アトミックアトミックオペレーション12の主なカテゴリー、アトミック更新モードの四種類、原子の基本的なタイプ、アトミック更新アレイ、フィールドの更新原子、アトミック更新基準を更新します。アトミックパッケージラッパークラスは、基本的に危険が実装に使用されます。

基本タイプ:のAtomicInteger、AtomicLong、AtomicBoolean。

リファレンスタイプ:AtomicReference、AtomicReference、AtomicStampedRerence、AtomicMarkableReferenceのABA例。

配列型:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray。

原子修飾子(アップデータ)の属性:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater。

図1に示すように、基本的なアトミック更新型クラス

  AtomicBoolean:ブールアトミック更新原子の基本的な種類を更新するための手段によって、アトミックパッケージは、次の3つのカテゴリが用意されています。AtomicInteger:原子更新整数。AtomicLong:アトミック更新長整数。以下の通りのAtomicInteger一般的な方法があります。int addAndGet(INTデルタ):(のAtomicInteger値の)数値実施例アトミック入力値を加え、その結果ブールのcompareAndSet(intは期待する、INTの更新)を返しています入力場合値は、入力値のアトミック設定値の値に等しいです。int型getAndIncrement():原子的に現在の値に1を加え、注意:これは正面から返された値です。無効lazySet(INT newValueに):最終的に設定newValueに、まだ古い値を読み取ることができた後、使用lazySetの設定は、短い時間内に他のスレッドを引き起こすことが後。INT getAndSet(INT newValueに):アトミックnewValueにの値に設定され、値を返します。アトミックパッケージには、原子更新の3つの基本タイプを提供していますが、fldoubleなどのJavaのcharの基本的なタイプは、まだあります。そこで問題は、どのように原子それの他の基本的なタイプを更新していますか?アトミックバッグ安全でないのでアトミック更新DOU、まず、その後、CASのためcompareAndSwapIntを使用したブールを整数に変換し、AtomicBooleanのソースを見て、基本的なクラス、3つだけの危険CAS方式、compareAndSwapObject、compareAndSwapIntとcompareAndSwapLongを使用して実装しましたまた、同様のアイデアを実現することができます。

ここでは、各タイプの例を見て:

コードをコピー
/ **   
* <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、参照型アトミック更新

あなたが複数の変数原子を更新する場合のAtomicIntegerのアトミック更新の基本的なタイプは、唯一、変数を更新することができ、原子更新は、あなたが提供する、このクラスの参照型を使用する必要があります。AtomicReference:アトミック更新参照型アトミックパッケージには、次の3つのカテゴリが用意されています。AtomicReferenceFieldUpdater:フィールドの原子更新参照型。AtomicMarkableReference:参照型原子マーク位置を更新します。原子はブーリアンフラグ及び基準タイプを更新することができます。コンストラクタはAtomicMarkableReference(V initialRef、ブールinitialMark)であります

次は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操作に失敗しました
コードをコピー
3、配列型アトミック更新
  アトミック更新整数配列要素:ところで原子によって配列の要素を更新し、アトミックパッケージは、次の3つのカテゴリAtomicIntegerArrayを提供します。AtomicLongArray:アトミック更新長い整数の配列要素。AtomicReferenceArray:アトミック更新参照型配列要素。提供omicIntegerArray主要実施形態は、その通常の方法INT addAndGetに配列整数原子を更新する(I、INTデルタINT):アトミックミシソーガ入力値アレイ。ブールのcompareAndSetは、(i、intは期待する、INTの更新INT):値がアトミックiが設定されている位置での配列の要素が値を更新する場合。

次は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、アトミック更新フィールドクラス

我々は唯一のフィールドでクラスを必要がある場合は、原子更新フィールドクラスを使用する必要があり、アトミック言及パッケージ
次の三つのカテゴリーの場合:
AtomicIntegerFieldUpdater:アトミック更新アップデータの整数フィールド。
AtomicLongFieldUpdater:アトミック更新アップデータ長い整数フィールド。
AtomicStampedReference:参照型のアトミック更新のバージョン番号。そのような整数値
より多くのデータと、それは原子のために使用することができる基準データに関連付けられたバージョン番号は、原子CASを用いて解くことができます
発生する可能性があり、更新、ABAの問題。静的メソッドを作成するときにアトミック更新フィールドクラスは抽象クラスであり、それぞれの使用が使用する必要がありますnewUpdater
アップデータ。フィールドアトミックアップデートは、公開volatile型修飾子を使用する必要があります。

次は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(){ 
          戻り年齢;
 

おすすめ

転載: www.cnblogs.com/aa1122/p/11706155.html