19-java中的CAS

CAS

CAS,compare and swap的縮寫,中文翻譯成比較並交換。

CAS 操作包含三個操作數 —— 內存位置(V)、預期原值(A)和新值(B)。如果內存位置的值與預期原值相匹配,那麼處理器會自動將該位置值更新爲新值 。否則,處理器不做任何操作。無論哪種情況,它都會在 CAS 指令之前返回該 位置的值。(在 CAS 的一些特殊情況下將僅返回 CAS 是否成功,而不提取當前 值。)CAS 有效地說明了“我認爲位置 V 應該包含值 A;如果包含該值,則將 B 放到這個位置;否則,不要更改該位置,只告訴我這個位置現在的值即可。”

通常將 CAS 用於同步的方式是從地址 V 讀取值 A,執行多步計算來獲得新 值 B,然後使用 CAS 將 V 的值從 A 改爲 B。如果 V 處的值尚未同時更改,則 CAS 操作成功

很多地方說CAS操作是非阻塞的,其實系統底層進行CAS操作的時候,會判斷當前系統是否爲多核系統,如果是就給總線加鎖,所以同一芯片上的其他處理器就暫時不能通過總線訪問內存,保證了該指令在多處理器環境下的原子性。總線上鎖的,其他線程執行CAS還是會被阻塞一下,只是時間可能會非常短暫,所以說CAS是非阻塞的並不正確,只能說阻塞的時間是非常短的。

java中提供了對CAS操作的支持,具體在sun.misc.Unsafe類中,聲明如下:

public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

上面三個方法都是類似的,主要對4個參數做一下說明。

  • var1:表示要操作的對象
  • var2:表示要操作對象中屬性地址的偏移量
  • var4:表示需要修改數據的期望的值
  • var5:表示需要修改爲的新值

synchronized、ReentrantLock這種獨佔鎖屬於悲觀鎖,它是在假設需要操作的代碼一定會發生衝突的,執行代碼的時候先對代碼加鎖,讓其他線程在外面等候排隊獲取鎖。悲觀鎖如果鎖的時間比較長,會導致其他線程一直處於等待狀態,像我們部署的web應用,一般部署在tomcat中,內部通過線程池來處理用戶的請求,如果很多請求都處於等待獲取鎖的狀態,可能會耗盡tomcat線程池,從而導致系統無法處理後面的請求,導致服務器處於不可用狀態。

除此之外,還有樂觀鎖,樂觀鎖的含義就是假設系統沒有發生併發衝突,先按無鎖方式執行業務,到最後了檢查執行業務期間是否有併發導致數據被修改了,如果有併發導致數據被修改了 ,就快速返回失敗,這樣的操作使系統併發性能更高一些。cas中就使用了這樣的操作。

CAS 的問題

ABA問題
CAS需要在操作值的時候檢查下值有沒有發生變化,如果沒有發生變化則更新,但是如果一個值原來是A,變成了B,又變成了A,那麼使用CAS進行檢查時會發現它的值沒有發生變化,但是實際上卻變化了。這就是CAS的ABA問題。常見的解決思路是使用版本號。在變量前面追加上版本號,每次變量更新的時候把版本號加一,那麼A-B-A 就會變成1A-2B-3A。目前在JDK的atomic包裏提供了一個類AtomicStampedReference來解決ABA問題。這個類的compareAndSet方法作用是首先檢查當前引用是否等於預期引用,並且當前標誌是否等於預期標誌,如果全部相等,則以原子方式將該引用和該標誌的值設置爲給定的更新值。

循環時間長開銷大
如果CAS不成功,則會原地循環(自旋操作),如果長時間自旋會給CPU帶來非常大的執行開銷。併發量比較大的情況下,CAS成功概率可能比較低,可能會重試很多次纔會成功。

關於原子類操作,都位於java.util.concurrent.atomic包中

第21天:java中的CAS

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