java - AtomicInteger 的CAS 問題
我想大声告诉你
我想大声告诉你 2017-06-28 09:24:31
0
1
723
public final int incrementAndGet() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return next; } }

這是自增操作,定義: CAS有3個操作數,記憶體值V,舊的預期值A,要修改的新值B。當且僅當預期值A和記憶體值V相同時,將記憶體值V修改為B,否則什麼都不做
預期值是next嗎?記憶體值是current?
假如1個執行緒自增時沒有其他執行緒競爭,那麼預期值應該比記憶體值大1啊,怎麼會預期值和記憶體值相同?

我想大声告诉你
我想大声告诉你

全部回覆 (1)
刘奇

瀉藥~
可能題主這裡理解有點偏差

  1. current是預期值,不是記憶體值

  2. next是修改的新值不是預期值

方法compareAndSet的源碼就可以看得出來,裡面註釋已經很明白了

/** * Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * * @param expect the expected value * @param update the new value * @return {@code true} if successful. False return indicates that * the actual value was not equal to the expected value. */ public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); }

CAS的操作是按照題主所說,用預期值和內存值比較,只有當相等時,才會把新值寫入,否則會不斷重試,是一種樂觀的態度,而真正的內存值其實是AtomicInteger.value這個屬性(其實最關鍵也不是這個屬性,只是個引用而已,真正的boss後面會提到),注意這個value的有關鍵字volatile修飾

private volatile int value;

所以這個value值其實是一個共享變量,代表著這個變量的可見性,也就是線程之間的可見性,

=======================話多隨便扯了哈可見性,不喜可以直接略過=========== =====================

簡單點說,Java記憶體模型規定了變數是存在主記憶體中(類似物理記憶體)的,各個執行緒都有自己的工作緩存,在對某個變數操作時,不是直接修改主記憶體中的值,而是在自己的工作快取中執行,最後在同步到主記憶體中,且執行緒相互之間的是不能存取對方的工作快取的

這裡說到的可見性,就是指,線程在操作有關鍵字volatile修飾的變數時,當成功修改了這個變數並寫入了主存,那麼其他執行緒的工作快取中的變數會失效,所以此時其他執行緒再去讀取變數時會直接從主記憶體去讀,而不會再用自己工作快取中的值了

========================================== 扯完===== =========================================

剛才說到AtomicInteger.value這個屬性對於資料本身而言,只是一個引用,在呼叫compareAndSet方法時,可以注意到第二個參數,valueOffset,其實這才是關鍵...的Boss,真正的記憶體的值,因為涉及到在java語言裡很少聽到的一個詞,指針,這個valueOffset其實就是對象內的偏移量啦,這才是真正的內存值

(之所以這個方法compareAndSet裡調用的是Unsafe類的方法,Unsafe這其實就是封裝了一些類似指針的操作,指針才不安全)

    最新下載
    更多>
    網站特效
    網站源碼
    網站素材
    前端模板
    關於我們 免責聲明 Sitemap
    PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!