併發系列(四)-----CAS

一 簡介

 保證Java中的原子操作方式有兩種方式
  1 加鎖(能夠理解悲觀鎖機制)
  2 CAS(能夠理解爲樂觀鎖機制)
  CAS全稱是Compare and Swap 即比較並替換。在JDK中許多地方均可以看到它的身影,好比AQS同步組件,Atomic原子類操做等等都是以CAS實現的。其中java.util.concurrent 中的許多概念源自 Doug Lea 的 util.concurrent 庫,而Doug lea大神在同步組件中大量使用使用CAS技術鬼斧神工地實現了Java多線程的併發操做。java


 二 CAS原理

在CAS中有三個參數:內存值V、舊的預期值A,要更新的值B。更新一個變量的時候,只有當變量的預期值A和內存地址V當中的實際值相同時,纔會將內存地址V對應的值修改成B。
來看一下Atomic包的源碼中是如何使用的CAS,並分析它的原理
AtomicInteger的成員變量多線程

     // setup to use Unsafe.compareAndSwapInt for updates 
     private static final Unsafe unsafe = Unsafe.getUnsafe();
     private static final long valueOffset;
     static {
        try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }
    private volatile int value;

  

AtomicInteger的成員變量進行說明
1 Unsafe 
Java語言不像C,C++那樣能夠直接訪問底層操做系統,可是JVM爲咱們提供了一個後門,這個後門就是unsafe。unsafe爲咱們提供了硬件級別的原子操做 。
2 valueOffset
至於valueOffset對象,是經過unsafe.objectFieldOffset方法獲得,所表明的是AtomicInteger對象value成員變量在內存中的偏移量。咱們能夠簡單地把valueOffset理解爲value變量的內存地址。
3 value
被volatile所修飾被volatile的特色就不在說明了上一篇文章已經提到過了。
AtomicInteger的compareAndSet()併發

  /**
     * Atomically sets the value to the given updated value
     * if the current value {@code ==} the expected value.
     *
     * @param expect the expected value
     * @param update the new value
     * @return {@code true} if successful. False return indicates that
     * the actual value was not equal to the expected value.
     */
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
    //Unsafe.class
    public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

 

這個方法是修改值的方法,參數要求傳兩個參數指望值和要更新的值,若是更新成功的話返回true,反之亦然。在方法內部調用的是Unsafe的compareAndSwapInt,傳而unsafe的compareAndSwapInt方法參數包括了這三個基本元素:valueOffset參數表明了V,expect參數表明了A,update參數表明了B。app

正是unsafe的compareAndSwapInt方法保證了Compare和Swap操做之間的原子性操做。this


三 CAS的問題


 1.ABA問題
由於CAS須要在操做值的時候,檢查值有沒有發生變化,若是沒有發生變化則更新,可是若是一個值原來是A,變成了B,又變成了A,那麼使用CAS進行檢查時會發現它的值沒有發生變化,可是實際上卻變化了。ABA問題的解決思路就是使用版本號。在變量前面追加上版本號,每次變量更新的時候把版本號加1,那麼A→B→A就會變成1A→2B→3A。從Java 1.5開始,JDK的Atomic包裏提供了一個類AtomicStampedReference來解決ABA問題。這個類compareAndSet方法的做用是首先檢查當前引用是否等於預期引用,而且檢查當前標誌是否等於預期標誌,若是所有相等,則以原子方式將該引用和該標誌的值設置爲給定的更新值。
2.循環時間長CPU開銷大
自旋CAS若是長時間不成功,會給CPU帶來很是大的執行開銷
3.只能保證一個共享變量的原子操作spa

相關文章
相關標籤/搜索