Java多線程之通俗易懂講解CAS

什麼是CAS機制

CAS即CompareAndSet被稱之爲無鎖優化,從設計思想來說CAS屬於樂觀鎖

CAS原理

int count = 0;
compareAndSet(count, 1, 2)

此代碼塊需要對count執行加1操作此處的count就相當於下圖中的valueOffset,1就相當expect,2就相當於update,如果expect等於valueOffset纔會將count設爲2也就是圖中的update,如果不相等則重新預估expect的值直到成功爲止,這個不斷預估expect值的過程稱之爲自旋,是在內存中進行的。
在這裏插入圖片描述
爲什麼要進行count是否等於expect的比較呢?我們可以想象一種 高併發的場景,有多個線程需要同時對count進行加1操作如果線程1一開始獲取到了count的值爲1,此時的expect值爲1,update爲2,當線程1還沒執行完對count的加1操作時CPU分配給線程1的時間片到了,這個時候線程2進來了執行了對count的一個自增操作count變爲了2,當再次輪到線程1操作時如果不進行valueOffset是否等於expect的操作就會導致count重新變回1,這樣就出現了線程不安全的問題。

CAS機制代碼演示

在這裏插入圖片描述

ABA問題以及解決方案

  • 線程1獲取到如下的值,CPU使用時間片到了,進入到了等待狀態
    在這裏插入圖片描述
  • 這時線程2獲得CPU資源將值修改爲10
    在這裏插入圖片描述
  • 接着又將值修改回到3
    在這裏插入圖片描述
  • 接着線程1又獲取到了CPU資源,這是對於線程1來說valueOffset相當於沒有變,這就是ABA問題
    在這裏插入圖片描述
  • 如果valueOffset爲整數ABA問題是沒有影響的但是當我們把valueOffset引申爲對象,這就不一定了因爲對象在這個變來變去的過程中可能改變了其中屬性的值,如何解決ABA問題,添加一個版本號version就能有效的解決,每進行一次操作時就對version進行加1操作,每次操作前同時進行version的校驗

CAS機制的缺點

  • CPU開銷較大
    在併發量比較高的情況下,如果許多線程反覆嘗試更新某一個變量,卻又一直更新不成功,循環往復,會給CPU帶來很大的壓力。
  • 不能保證代碼塊的原子性
    CAS機制所保證的只是一個變量的原子性操作,而不能保證整個代碼塊的原子性。比如需要保證3個變量共同進行原子性的更新,就不得不使用Synchronized了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章