Javaの並行処理---原子CAS

2つの方法の同時動作を実現する方法であって、一つは、ロック(同期してロック)を使用することで別のアトミック操作(CAS)の使用であります

シンクロナイズドベースのロック機構は、問題の閉塞を引き起こすことがあります。

。優先度の高いスレッドブロックされた
Bを。ロックが行う方法となっているロック・スレッドのリリースを得ることはありませんか?
デッドロックやその他のセキュリティ上の問題をもたらしながら、C。競争の多くは、CPUを消費します

上記の問題を踏まえ、CAS原子
a.CAS原則:それは成功するまで、最新のプロセッサのCAS命令の使用は、このサイクルのコマンドをサポートしている
、これはアトミック操作であることを保証のレベルの指示:b.CAS(比較とスワップ)
C CASに関連する3つの演算子:メモリアドレスV、所望の値、Bの新しい値は
基本的な考え方:新しい値V Bを割り当てるアドレスを与え、に等しく、そうでない場合はアドレスの値場合とVの所望の値に、何もしません。
(連続運転CASのIn(無限ループ)サイクル)

d.CASはまた、いくつかの質問があります。

1)ABA問題(A-> B-> A):第一のメモリアドレスVをフェッチする場合、Aの値を取るが、前にCAS操作は、スレッドBにAの値を有する場合に行うことができます後に、同じものの、この時の、値に変更しましたが、内容が変更されました。(例:それはまだ水のコップで満たされているが、現実には、あなたが再び明らかにそこにカップを埋める、巣の上に私の同僚の上に水のガラスを飲んでいる、自然は完全です。 )溶液のように:あなたが解決することができるA1-> B2 ----> A3(同様に楽観的ロック、データのバージョン(バージョンベースのほとんどの)バージョン番号を記録することによって実現メカニズム)。

2)オーバーヘッド問題:CAS長期操作が成功しない、CPU連続サイクル。

3)のみ共有変数アトミック動作を保証

アトミック操作のクラスを使用して:
JDKは、クラスに関連するアトミック操作を使用して:
1)更新の基本タイプ:AtomicBoolean、のAtomicInteger、AtomicLong
のAtomicIntegerの単純なサンプルコード()

関連した方法は、比較的簡単である:getAndIncrement()値1を加えに
incrementAndGet ()第一とその値を追加する1

package 原子操作;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author lenovo
 */
public class UseAtomicInt {

    static AtomicInteger ai=new AtomicInteger(10);

    public static void main(String[] args) {
        //先取值再加1
        System.out.println(ai.getAndIncrement());
        //先加1再取值
        System.out.println(ai.incrementAndGet());
        System.out.println(ai.get());
    }
}

:結果は、
ここに画像を挿入説明
2)配列クラスを更新:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
単純なコード例(AtomicIntegerArray)
値を変更する場合、実際には、元の配列の値が変更されていない、配列のコピー、および再割り当てです。

package 原子操作;

import java.util.concurrent.atomic.AtomicIntegerArray;

/**
 * @author lenovo
 */
public class AtomicArray {

    static int []value=new int[]{1,2};

    static AtomicIntegerArray ai = new AtomicIntegerArray(value);

    public static void main(String[] args) {
        //第一个参数代表原数组的下标值 第二个参数代表值
        ai.getAndSet(0,3);
        System.out.println(ai.get(0));
        System.out.println(value[0]);

    }
}

結果を示している(新しい配列の変更後の結果を示す第1の値を、第2の結果は、元の配列の値を表す)、
ここに画像を挿入説明
3)は、基準タイプ更新:AtomicReference、AtomicMarkableReferenceをAtomicStampedReference
参照型アトミック操作クラスは、複数のデータをカプセル化します複数の変数は、アトミック動作に達した
:簡単なコードサンプル(AtomicReferenceを)
のUserInfoこれら二つの変数の名前と年齢をパッケージのこのタイプ、変更された値は、再コピーされたとき、及び、値を変更します。

package 原子操作;

import java.util.concurrent.atomic.AtomicReference;

/**
 * @author lenovo
 * 类说明:演示引用类型的原子操作类
 */
public class UseAtomicReference {

    static AtomicReference<UserInfo> userRef=new AtomicReference<UserInfo>();

    public static void main(String[] args) {
        UserInfo user=new UserInfo("zs",15);
        userRef.set(user);

        UserInfo updateUser=new UserInfo("ls",17);
        //这是候的更改是在新生成得对象进行变更
        userRef.compareAndSet(user,updateUser);
        System.out.println(userRef.get().getName());
        System.out.println(userRef.get().getAge());
        System.out.println(user.getName());
        System.out.println(user.getAge());


    }

    static class UserInfo{
        private String name;
        private int age;

        public UserInfo(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }
        public int getAge() {
            return age;
        }


    }
}


結果は、(最初​​の2つの値が変更後の基準値を表す2つの値は、引用元の値を表します):
ここに画像を挿入説明

4)Updateフィールドクラス:AtomicReferenceFieldUpdater、AtomicIntegerFieldUpdater、AtomicLongFieldUpdater(めったに使われません)

解决ABA问题的两个类: AtomicMarkableReference 处理版本使用的是boolean (表示有没有动过)
AtomicStampedReference: 表示动过几次(它的构造函数为AtomicStampedReference(V initialRef, int initialStamp ) 第一个参数表示引用类型的值,第二参数表示版本号 )

简单代码示例(AtomicStampedReference具有较强的实用性,表示的是当我们遇到ABA问题时可采用版本号进行分辨后操作)
该代码中有两个线程对带有版本戳的类进行更改,其中一个线程是在版本正确的情况对引用类型的值进行更改(这种情况下是可以更改成功的)另外一个线程是在版本不正确的情况下对引用类型的值进行更改(这种情况下是更改失败的)
compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) 返回的结果值是Boolean表示更改成功或者失败
其中第一个参数表示期待的引用值,第二个表示新的引用值。
第三个参数表示的是期待的版本戳,第四个表示新的版本戳

package 原子操作;

import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * @author lenovo
 * 演示带版本戳的原子操作类
 */
public class UseAtomicStampedReference {

    //AtomicStampedReference(V initialRef, int initialStamp) 传初始值和版本号
    static AtomicStampedReference<String> asr=
            new AtomicStampedReference<String>("Mark",0);

    public static void main(String[] args) throws InterruptedException {
        final int oldStamp=asr.getStamp();
        final String oldReference=asr.getReference();

        System.out.println(oldReference+"======"+oldStamp);

        //正确版本号的线程
        Thread rightStampThread=new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+
                        "当前变量值为:"+oldReference+" 当前版本号为:"+oldStamp+"-"
                        +asr.compareAndSet(oldReference,oldReference+" Java",
                        oldStamp,oldStamp+1));


            }
        });

        //错误版本号的线程
        Thread errorStampThread=new Thread(new Runnable() {
            @Override
            public void run() {

                System.out.println(Thread.currentThread().getName()+
                        "当前变量值为:"+asr.getReference()+" 当前版本号为:"+asr.getStamp()+"-"
                        +asr.compareAndSet(asr.getReference(),asr.getReference()+" C",
                        oldStamp,oldStamp+1));


            }
        });

        rightStampThread.start();
        rightStampThread.join();
        errorStampThread.start();
        errorStampThread.join();
        System.out.println(asr.getReference()+"======"+asr.getStamp());
    }
}

结果展示(第一行的值表示的是原本引用类型的值和版本号 第二行的值表示的是一个在正确版本戳下对引用类型值的改变
第三行的值表示的是在一个错误版本戳下对引用值类型的改变,第四行代表的更改后最终的结果值)
ここに画像を挿入説明

发布了19 篇原创文章 · 获赞 2 · 访问量 418

おすすめ

転載: blog.csdn.net/TheWindOfSon/article/details/103863601