天天看點

原子操作CAS并發程式設計–原子操作CAS

并發程式設計–原子操作CAS

1.預備概念

CAS:(compared and sweep)比較後進行交換,是一種樂觀鎖的設計思想。

synchronized:是以一種基于悲觀鎖的實作。

原子操作:不會被線程排程機制打斷的操作;這種操作一旦開始,就一直運作到結束,中間不會有任何上下文切換,在x86 平台上,CPU提供了在指令執行期間對總線加鎖的手段,需要硬體支援。

2.CAS原理

一.實作原理:

流程

比較後進行交換,當更新值的時候,帶上舊值,如果舊值和目前變量的值相等,那就認為該資料沒有被更其他線程操作過,再把新值指派給該變量。

  1. 第一步目前線程通過舊值經過計算得到新值。
  2. compare記憶體中變量值和舊值,如果相等進入下一步。
  3. 舊值swap為新值。

帶來的問題:

  1. ABA問題:利用CAS確定原子性,會帶來ABA問題,是以常見的CAS一般帶有版本号來确定是否有ABA問題。***cas(記憶體位址,舊值,新值)***。
  2. 開銷問題:當舊值和記憶體中的值不相等,重新進入一次計算,可能導緻死循環。
  3. 效率問題:一次CAS隻能操作一個變量,當有多個變量需要組合更改。

利用CAS實作的原子操作類

更新基本類型的:AtomicBoolean AtomicInteger AtomicLong

更新數組的:AtomicIntegerArray AtomicLongArray

更新引用類型的:AtomicReference AtomicMarkableReference.

AtomicIntegerArray 測試:

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerArray;

public class AtomicIntegerTest {

    public static void main(String[] args) {
        int [] integers = new int[]{1,2};

        AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(integers);

        atomicIntegerArray.set(0,3);
        System.out.println(atomicIntegerArray.get(0));
        System.out.println(integers[0]);
    }
}
           

運作結果:

3
1
~~~java
AtomicMarkedReference:通過boolean是否修改的方式保持原子性。
AtomicStampReference:通過版本戳的形式去保持原子更新,更新的版本可控。

測試代碼:AtomicMarkedReferenceTest
package cn.enjoyedu.ch3;

import java.util.concurrent.atomic.AtomicMarkableReference;
import java.util.concurrent.atomic.AtomicStampedReference;

public class AtomicStampReferenceTest {

    public static void main(String[] args) throws InterruptedException {
        AtomicReferenceTest.UserInfo userInfo = new AtomicReferenceTest.UserInfo("james", 20);
        //聲明一個引用
//        AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference = new AtomicStampedReference<AtomicReferenceTest.UserInfo>(userInfo,0);
        AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference = new AtomicMarkableReference<AtomicReferenceTest.UserInfo>(userInfo,false);

        //聲明兩個線程去修改
        Thread thread = new Thread(new ThreadModify1(atomicStampedReference));
        thread.start();
        thread.join();
        Thread thread2 = new Thread(new ThreadModify2(atomicStampedReference));
        thread2.start();

    }
    static class ThreadModify1 extends Thread{
        AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference ;
        public ThreadModify1(AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference){
            this.atomicStampedReference = atomicStampedReference;
        }
        @Override
        public void run() {
            //擷取值和版本号
            AtomicReferenceTest.UserInfo userInfo = atomicStampedReference.getReference();
            //stamp
            boolean stamp = atomicStampedReference.isMarked();
            AtomicReferenceTest.UserInfo deer = new AtomicReferenceTest.UserInfo("deer", 100);
            boolean b = atomicStampedReference.compareAndSet(userInfo, deer, stamp, false);
            System.out.println(currentThread().getName()+b);
        }
    }

    static class ThreadModify2 extends Thread{
        AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference ;
        public ThreadModify2(AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference){
            this.atomicStampedReference = atomicStampedReference;
        }
        @Override
        public void run() {
            //擷取值和版本号
            AtomicReferenceTest.UserInfo userInfo = atomicStampedReference.getReference();
            //stamp
            boolean stamp = atomicStampedReference.isMarked();
            AtomicReferenceTest.UserInfo deer = new AtomicReferenceTest.UserInfo("deer", 100);
            boolean b = atomicStampedReference.compareAndSet(userInfo, deer, stamp, false);
            System.out.println(currentThread().getName()+b);
        }
    }


}
           

運作結果:

Thread-1true
Thread-3false
           

測試代碼:AtomicStampReferenceTest

import java.util.concurrent.atomic.AtomicMarkableReference;
import java.util.concurrent.atomic.AtomicStampedReference;

public class AtomicStampReferenceTest {

    public static void main(String[] args) throws InterruptedException {
        AtomicReferenceTest.UserInfo userInfo = new AtomicReferenceTest.UserInfo("james", 20);
        //聲明一個引用
        AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference = new AtomicStampedReference<AtomicReferenceTest.UserInfo>(userInfo,0);

        //聲明兩個線程去修改
        Thread thread = new Thread(new ThreadModify1(atomicStampedReference));
        thread.start();
        thread.join();
        Thread thread2 = new Thread(new ThreadModify2(atomicStampedReference));
        thread2.start();

    }
    static class ThreadModify1 extends Thread{
        AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference ;
        public ThreadModify1(AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference){
            this.atomicStampedReference = atomicStampedReference;
        }
        @Override
        public void run() {
            //擷取值和版本号
            AtomicReferenceTest.UserInfo userInfo = atomicStampedReference.getReference();
            //stamp
            int stamp = atomicStampedReference.getStamp();
            AtomicReferenceTest.UserInfo deer = new AtomicReferenceTest.UserInfo("deer", 100);
            boolean b = atomicStampedReference.compareAndSet(userInfo, deer, stamp, stamp + 2);


            System.out.println(currentThread().getName()+b);
        }
    }

    static class ThreadModify2 extends Thread{
        AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference ;
        public ThreadModify2(AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference){
            this.atomicStampedReference = atomicStampedReference;
        }
        @Override
        public void run() {
            //擷取值和版本号
            AtomicReferenceTest.UserInfo userInfo = atomicStampedReference.getReference();
            //stamp
            int stamp = 0;
            //atomicStampedReference.getStamp();
            AtomicReferenceTest.UserInfo deer = new AtomicReferenceTest.UserInfo("deer", 100);
            boolean b= atomicStampedReference.compareAndSet(userInfo,deer,stamp,stamp+2);
            System.out.println(currentThread().getName()+b);
        }
    }


}

           

運作結果:

Thread-1true
Thread-3false
           

繼續閱讀