劍指Offer(鎖)——CAS

CAS是一種高效實現線程安全性的方法:

  1. 支持原子性的更新操作,適用於計數器,序列發生器等場景;
  2. 屬於樂觀鎖機制,號稱lock-free(無鎖),但是實際上還是存在底層鎖的;
  3. CAS操作失敗時候由開發者決定是繼續嘗試還是執行別的操作。

CAS操作思想:

包含三個操作數——內存位置(V)、預期原值(A)、新值(B)

比較時候由內存位置和預期原值去進行對比,如果是相同的就會將內存位置的值更新爲新值否則處理器不做任何操作,內存位置的值指的是主內存的值。

舉個簡單的例子:當一個CAS操作想要修改共享變量的值要完成這個操作需要先取出共享變量的值給A,然後基於A的基礎去進行計算得到新值B,當執行完畢之後需要更新共享變量的時候可以調用CAS方法去更新變量的值。
在這裏插入圖片描述
將其編譯然後用javap看一下字節碼的操作指令:
在這裏插入圖片描述
可以看出add方法的value++操作分成了兩個部分,getfield操作將value值加載進當前線程的工作內存中然後執行iadd操作將其加一,最後執行putfield將value值寫入主內存中,使用了volatile可以保證線程之間的可見性,但是不能保證原子性,在多線程下是不安全的那麼該如何解決呢???

解決方法有兩種:

  1. 使用synchronized,加上互斥鎖
    在這裏插入圖片描述
  2. 使用Atomic原子操作
    在這裏插入圖片描述

總結:

  1. CAS在大多數情況下對於開發者來說是透明的因爲不需要操作指令重排;
  2. JUC下的atomic包提供了常用的原子性數據類型以及引用、數組等相關原子類型和更新操作工具,是很多線程安全程序的首選;
  3. Unsafe雖然有CAS操作但是因爲能夠任意操作內存地址讀寫存在隱患;
  4. JDK9中,可以使用Variable Handle API替換Unsafe。

CAS操作也是存在缺點的:

  1. 如果循環時間過長,開銷就會很大;
  2. 只能保證一個共享變量的原子操作;
  3. ABA問題(解決方法:使用AtomicStampedReference基於變量版本控制檢查是否發生值的替換)。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章