java - AtomicInteger 的CAS 問題
問題描述
public final int incrementAndGet() {for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next))return next;} }
這是自增操作,定義: CAS有3個操作數(shù),內(nèi)存值V,舊的預(yù)期值A(chǔ),要修改的新值B。當(dāng)且僅當(dāng)預(yù)期值A(chǔ)和內(nèi)存值V相同時,將內(nèi)存值V修改為B,否則什么都不做預(yù)期值是next嗎? 內(nèi)存值是current?假如1個線程自增時沒有其他線程競爭,那么預(yù)期值應(yīng)該比內(nèi)存值大1啊,怎么會預(yù)期值和內(nèi)存值相同?
問題解答
回答1:瀉藥~可能題主這里理解有點偏差
current是預(yù)期值,不是內(nèi)存值
next是修改的新值不是預(yù)期值
方法compareAndSet的源碼就可以看得出來,里面注釋已經(jīng)很明白了
/** * 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的操作是按照題主所說,用預(yù)期值和內(nèi)存值比較,只有當(dāng)相等時,才會把新值寫入,否則會不斷重試,是一種樂觀的態(tài)度,而真正的內(nèi)存值其實是AtomicInteger.value這個屬性(其實最關(guān)鍵也不是這個屬性,只是個引用而已,真正的boss后面會提到),注意這個value的有關(guān)鍵字volatile修飾
private volatile int value;
所以這個value值其實是一個共享變量,代表著這個變量的可見性,也就是線程之間的可見性,
=======================話多隨便扯了哈可見性,不喜可以直接略過================================
簡單點說,Java內(nèi)存模型規(guī)定了變量是存在主存中(類似物理內(nèi)存)的,各個線程都有自己的工作緩存,在對某個變量操作時,不是直接修改主存中的值,而是在自己的工作緩存中執(zhí)行,最后在同步到主存中,并且線程相互之間的是不能訪問對方的工作緩存的
這里說到的可見性,就是指,線程在操作有關(guān)鍵字volatile修飾的變量時,當(dāng)成功修改了這個變量并寫入了主存,那么其他線程的工作緩存中的變量會失效,所以此時其他線程再次去讀取變量時會直接從主存中去讀,而不會再用自己工作緩存中的值了
==========================================扯完==============================================
剛才說到AtomicInteger.value這個屬性對于數(shù)據(jù)本身而言,只是一個引用,在調(diào)用compareAndSet方法時,可以注意到第二個參數(shù),valueOffset,其實這才是關(guān)鍵...真正的Boss,真正的內(nèi)存的值,因為涉及到在java語言里很少聽到的一個詞,指針,這個valueOffset其實就是對象內(nèi)的偏移量啦,這才是真正的內(nèi)存值
(之所以這個方法compareAndSet里調(diào)用的是Unsafe類的方法,Unsafe這其實就是封裝了一些類似指針的操作,指針才不安全嘛)
相關(guān)文章:
1. phpstudy8.1沒集成mysql-front2. Docker for Mac 創(chuàng)建的dnsmasq容器連不上/不工作的問題3. node.js - mongodb查找子對象的名稱為某個值的對象的方法4. docker鏡像push報錯5. 關(guān)docker hub上有些鏡像的tag被標(biāo)記““This image has vulnerabilities””6. docker 下面創(chuàng)建的IMAGE 他們的 ID 一樣?這個是怎么回事????7. 利用IPMI遠(yuǎn)程安裝centos報錯!8. html5 - datatables 加載不出來數(shù)據(jù)。9. 前端 - @media query 使用出現(xiàn)的問題?10. html5和Flash對抗是什么情況?

網(wǎng)公網(wǎng)安備