原理剖析(第 004 篇)CAS工做原理分析

原理剖析(第 004 篇)CAS工做原理分析

-git

1、大體介紹

一、關於多線程競爭鎖方面,你們都知道有個CAS和AQS,也正是這兩個東西才引伸出了大量的線程安全類,鎖類等功能;
二、而隨着如今的硬件廠商愈來愈高級,在硬件層面提供大量併發原語給咱們Java層面的開發帶來了莫大的利好;
三、本章節就和你們分享分析一下CAS的工做原理;

2、原理分析

2.1 何爲CAS?

一、CAS,compare and swap的縮寫,顧名思義,比較再交換,即 「讀取-修改-寫操做」 三個步驟爲一體原子操做;

二、CAS操做包含三個參數:內存位置(V)、預期值(A)、新值(B);
   若是內存位置的值V與預期值A相匹配,那麼處理器會自動將該位置值更新爲新值B,不然不更新;

2.2 CAS原理

一、CAS經過JNI方式調用底層操做系統的C代碼,從而藉助底層C代碼來調用CPU底層操做指令來實現原子操做;

二、CAS是硬件CPU提供的原語,經過底層cmpxchg原語指令(多處理器再加上Lock指令)實現原子操做;

2.3 CAS核心源碼

一、CAS核心源碼:
// Adding a lock prefix to an instruction on MP machine
// VC++ doesn't like the lock prefix to be on a single line
// so we can't insert a label after the lock prefix.
// By emitting a lock prefix, we can define a label after it.
#define LOCK_IF_MP(mp) __asm cmp mp, 0  \
                       __asm je L0      \
                       __asm _emit 0xF0 \
                       __asm L0:

inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value) {
  // alternative for InterlockedCompareExchange
  int mp = os::is_MP();
  __asm {
    mov edx, dest
    mov ecx, exchange_value
    mov eax, compare_value
    LOCK_IF_MP(mp) // 若是是多處理器的話,則須要添加Lock前綴指令,Lock的方式和Volatile的實現方式雷同
    cmpxchg dword ptr [edx], ecx // 
  }
}

二、經過上述源碼能夠發現該cmpxchg方法會自動判斷當前是不是多處理器,多處理器的話則添加lock前綴指令,反之省略lock前綴;

三、至於lock是怎麼保證多處理器的一致性的話,原理和Volatile雷同,請移步看看[原理剖析(第 001 篇)Volatile工做原理分析];

3、CAS缺點

3.一、ABA問題

一、併發操做時,容易引發ABA問題;
   假設i初始值i=5,A線程作i++操做一次,B線程作i--操做一次,C線程經過判斷i=5時則對i進行更新新值;

二、這個時候C線程會認爲i仍是處於初始值,未被作過修改,可是卻不知AB線程已經都對i進行修改了一次;

三、爲了解決這種線程,須要讓C知道i已經被修改過了,所以在Java1.5引進了一個AtomicStampedReference類來解決ABA問題;

四、AtomicStampedReference這個類主要是給變量追加了版本號信息,每次變量更新的話版本號都會自增長一;

五、可是有的人會認爲AtomicMarkableReference也能解決ABA問題,其實不能根本解決只能在最大程度上下降ABA問題的出現;
   由於它是經過一個boolean來標記是否更改,本質就是隻有true和false兩種版原本回切換,只能下降ABA問題發生的概率,並不能阻止ABA問題的發生;

3.二、開銷大

一、隨便拿個CAS的Java層代碼:
    public final int getAndSetInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var4));

        return var5;
    }

二、經過這段代碼發現,若是CAS操做一直不成功的話,那麼該段代碼就一直在自旋操做,會給CPU帶來比較大的執行開銷;

3.三、原子操做約束

一、目前的CAS只能保證單個共享變量的原子操做;

二、可是對多個變量進行操做時,CAS沒法保證,可是能夠將多個變量封裝成一個新的對象,利用AtomicReference類來保證引用對象之間的原子性;

4、總結

一、咱們能夠在一些很是簡單的操做且又不想引入鎖的場景下采用CAS實現原子操做;

二、然而想要進行非阻塞的完成某些場景也能夠考慮採用CAS進行原子操做;

三、可是不推薦在很是複雜的操做中引入CAS,一來會使程序可讀性變差,二來且難以測試且會出現ABA問題。

5、下載地址

https://gitee.com/ylimhhmily/SpringCloudTutorial.git安全

SpringCloudTutorial交流QQ羣: 235322432微信

SpringCloudTutorial交流微信羣: 微信溝通羣二維碼圖片連接多線程

歡迎關注,您的確定是對我最大的支持!!!併發

相關文章
相關標籤/搜索