聊聊 CAS

哥有故事,你有酒,長夜漫漫,聽我給你說。編程

 參考資源:api

https://blog.csdn.net/hsuxu/article/details/9467651安全

 

1.概述併發

CAS,compare and swap ,「比較交換」的意思。它是一種併發狀態下的,比較交換的策略。性能

想必,咱們必定據說過樂觀鎖的概念,併發中樂觀鎖的核心概念就是應用了CAS。它包含了三個值:內存值,預期值和更新值。當內存值和預期值相等時,就會使用更新值將原來的數據(預期值)進行更新;若是不相等,則什麼都不作。atom

 

2.例子spa

舉個經典的例子,幫助你們理解。(僞代碼).net

 1  public class AtomicInt {
 2    private volatile int value;
 3    public final int get() {
 4        return value;
 5     }
 6 
 7 publicfinal int getAndIncrement() {
// 下面的for的無限循環,就是經典的CAS自旋(Compare and swap)
8 for (;;) { 9 int current = get(); 10 int next = current + 1; 11 if (compareAndSet(current, next)) 12 return current; 13 } 14 } 15 16 public final boolean compareAndSet(int expect, int update) { 17 unsafe.compareAndSwapInt方法(方法內部,使用JNI調用C的代碼); 18 } 19 }

 

3.凡事問個爲何.線程

爲何要比較?爲何要用CAS的自旋?直接設值不行嗎?它有什麼優勢缺點?code

例如,i++ 這個簡單的操做不是一步完成的,而是分了三步。第一步,取值,第二步加一,第三部更新值。

假設有A,B兩個線程同時操做i++這個處理,那麼,當線程A完成上述第二步的時候,線程B已經將I的值更新(第三步)作完了。這樣就會致使值發生異常,就是所謂的線程不安全。

因此,利用了樂觀鎖的思想採用了自旋的方式,每一次,就會先取得加一後的值,再將舊的值和內存中的值進行比較,若是相等,則說明,沒有被別的線程動過,所以能夠正常更新;若是不相等,則說明值已經被更新了,放棄本次的操做,從頭再來,再從新取值,加一,更新。

 

CAS自旋(樂觀鎖)避免了悲觀鎖獨佔的現象,同時提升了併發的性能。可是,它也是有缺點的。(第三點參考了其餘文章)

①樂觀鎖只能保證一個變量的的原子操做,多個變量的話,就沒有辦法了。

②長時間自旋,致使CPU消耗過大。

③ABA問題。CAS的核心思想是經過比對內存值與預期值是否同樣而判斷內存值是否被改過,可是,假如內存值原來是A,後來被一條線程改成B,最後又被改爲了A,則CAS認爲此內存值並無發生改變,但實際上,被其餘線程改過。這種狀況對依賴過程值的情景的運算結果影響很大。解決的思路是引入版本號,每次變量更新都把版本號加一。

 

4. 原子類Atomic

如今習慣多去查api文檔(這是個好的習慣)。在JUC的atomic包下有以下幾個類:

AtomicBoolean
AtomicInteger
AtomicLong
AtomicMarkableReference
AtomicReference

它們的原理都是應用了CAS的自旋,這幾個類在併發編程中常常用到,它們都是線程安全的類。

 

就聊這麼多,祝君美夢!

相關文章
相關標籤/搜索