CAS是什麼?AtomicInteger爲什麼使用CAS? AtomicInteger的底層原理是什麼?

1、CAS   即 Compare -And- Swap   比較並交換;

2、 通過AtomicInteger.compareAndSet();方法能夠解決多線程模式下i++計算結果出現的數據不一致的問題。

/**
 * @program: mybatis
 * @description: CAS
 * @author: Miller.FAN
 * @create: 2019-11-11 18:24
 **/
public class CASDome {

    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(5);
        System.out.println(atomicInteger.compareAndSet(5,2018)+"/t current data " + atomicInteger.get());
    }
}

3、AtomicInteger.compareAndSet()底層實現是什麼?

    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

4、unsafe.compareAndSwapInt(this, valueOffset, expect, update)的底層是什麼樣的?

    public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }
上面這段代碼就有意思了,他是Unsafe類種的一個方法,Unsafe中的方法都是直接調用操作系統底層資源執行相應的任務,即操作系統底層原語,不容許被打斷,不會造成所謂的數據不一致的問題。
var5 = this.getIntVolatile(var1, var2);中var1指當前對象,var2內存偏移地址。結果var5就是獲得的內存中的數據。
do {
    var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));    // 拿一下主內存地址中的值與自己保存的快照對比,如果一致就修改,如果不一致放棄修改,再做一次var5 = this.getIntVolatile(var1, var2);,直到主內存中的值與自己的快照值一直,海海皮皮的進行修改跳出循環,return var5+1;

5、爲什麼不直接使用Synchronized,而使用CAS呢?

殺雞焉用牛刀?Synchronized是重鎖,併發效率低。

6、CAS的缺點是什麼?

循環時間長,CPU開銷大。只能保證一個共享變量的一致性操作。不可避免的ABA問題。

7、ABA問題的演示和解決

public class AutmicRefence {
    
    static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
    static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100,1);

    public static void main(String[] args) {

        //ABA問題的演示
        new Thread(()-> {
            atomicReference.compareAndSet(100,101);
            atomicReference.compareAndSet(101,100);
        },"t1 ").start();

        new Thread(()-> {
            try{
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("current thread :" + atomicReference.compareAndSet(100,2049) + "/t current value: "+atomicReference.get());
        },"t2").start();

        //ABA問題的解決
        new Thread(()-> {
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "/t 第一次的本版號" + stamp);
            try{
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                e.printStackTrace();
            }
            atomicStampedReference.compareAndSet(100,101,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
            System.out.println(Thread.currentThread().getName() + "/t 第二次的本版號" + atomicStampedReference.getStamp());
            atomicStampedReference.compareAndSet(101,100,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
            System.out.println(Thread.currentThread().getName() + "/t 第三次的本版號" + atomicStampedReference.getStamp());
        },"t3 ").start();

        new Thread(()-> {
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "/t 第一次的本版號" + stamp);
            try{
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                e.printStackTrace();
            }
            boolean ret = atomicStampedReference.compareAndSet(100,101,stamp,stamp+1);
            System.out.println(Thread.currentThread().getName() + "/t 第二次的本版號" + atomicStampedReference.getStamp());
            System.out.println("修改成功否?" + ret);
            System.out.println("當前值是多少?" + atomicStampedReference.getReference());
        },"t4 ").start();
    }

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章