CAS總結


 

打開文件管理器Device File Explorer:

版本Android Studio3.2

 

 

 

什么是CAS

它是用在並發場合用來實現線程安全的一種算法,進行不可分割的原子操作。基本思想是:我認為value的值應該是A,如果是的話那我就把它改成B,如果不是A就說明已經被別人修改過了,那么我就不修改了,這就避免了並發情況下多人修改導致出錯。

CAS有三個操作數:內存值V、預期值A、要求改的值B。當且僅當預期值A和內存值V相同時,才將內存值修改為B,否則什么都不做。最后返回現在的V值。

CPU的特殊指令:CAS實際上是要利用CPU的特殊指令,這些指令由CPU保證了他們的原子性,一個指令就可以做好幾件事情,也不會出現線程安全問題。

 

案例

理解CAS的等價代碼:

public class SimulatedCAS {
   private volatile int value;

   public synchronized int compareAndSwap(int expectedValue, int newValue) {
       int oldValue = value;
       if (oldValue == expectedValue) {
           value = newValue;
      }
       return oldValue;
  }
}

 

 

應用場景

CAS在juc包中的應用是很多的,既能保證安全性,又能提高性能,不需要去獲取互斥同步鎖。CAS的第一個應用就是樂觀鎖,還有並發容器,以及原子類

 

以AtomicInteger為例,分析在Java中是如何利用CAS實現原子操作的

關於Java中是如何利用CAS實現原子操作:

  • AtomicInteger加載Unsafe工具,用來直接操作內存數據。

  • 所以實際上是通過Unsafe來實現底層操作。

    關於Unsafe類:

    Unsafe是CAS的核心類。Java無法直接訪問底層操作系統,而是通過本地native方法來訪問。不過盡管如此,JVM還是開啟了一個后門,JDK中的一個類Unsafe,提供了硬件級別的原子操作

    Unsafe代碼中的objectFieldOffset方法獲得的VALUE表示的是變量值在內存中的偏移地址,因為Unsafe就是根據內存偏移地址獲取數據的原值的,這樣我們就能通過Unsafe來實現CAS了。

  • 並且還需要volatile修飾value字段,保證可見性。

  • getAndAddInt方法分析

public class AtomicInteger extends Number implements java.io.Serializable {
   private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
   private static final long VALUE = U.objectFieldOffset(AtomicInteger.class, "value");
   //這個靜態變量會在最初被加載,
   //VALUE則是用Unsafe的objectFieldOffset取得的,拿到的是AtomicInteger這個類中value字段的地址。
   //而value正是用volatile修飾的
   private volatile int value;
   
   //省略。。。
   
   //分析getAndAdd方法
   public final int getAndAdd(int delta) {
       //調用的是Unsafe的getAndAddInt方法
       return U.getAndAddInt(this, VALUE, delta);
  }
}


class Unsafe{
   //省略。。。
   
   @HotSpotIntrinsicCandidate
   public final int getAndAddInt(Object o, long offset, int delta) {
       int v;
       do {
           v = getIntVolatile(o, offset);
      } while (!weakCompareAndSetInt(o, offset, v, v + delta));
       //可以看到上面是一個dowhile循環
       //而循環條件就調用了weakCompareAndSetInt,正是CAS的體現
       return v;
  }
   
   
   @HotSpotIntrinsicCandidate
   public final boolean weakCompareAndSetInt(Object o, long offset,
                                             int expected,
                                             int x) {
       return compareAndSetInt(o, offset, expected, x);
  }
   
   //到這里已經是一個native方法了
   //關於這個本地方法,它的C++代碼的思路是,利用偏移量拿到原值地址,然后進行相應的CAS操作
   @HotSpotIntrinsicCandidate
   public final native boolean compareAndSetInt(Object o, long offset,
                                                int expected,
                                                int x);
}
  • 總結

    Unsafe方法中的compareAndSetInt方法想辦法拿到變量value在內存中的地址。然后通過C++代碼實現原子性比較和替換

 

缺點

  • ABA問題

    可以添加版本號解決。

  • 自旋時間過長


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM