java - AtomicInteger 的CAS 問(wèn)題
問(wèn)題描述
public final int incrementAndGet() {for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next))return next;} }
這是自增操作,定義: CAS有3個(gè)操作數(shù),內(nèi)存值V,舊的預(yù)期值A(chǔ),要修改的新值B。當(dāng)且僅當(dāng)預(yù)期值A(chǔ)和內(nèi)存值V相同時(shí),將內(nèi)存值V修改為B,否則什么都不做預(yù)期值是next嗎? 內(nèi)存值是current?假如1個(gè)線程自增時(shí)沒(méi)有其他線程競(jìng)爭(zhēng),那么預(yù)期值應(yīng)該比內(nèi)存值大1啊,怎么會(huì)預(yù)期值和內(nèi)存值相同?
問(wèn)題解答
回答1:瀉藥~可能題主這里理解有點(diǎn)偏差
current是預(yù)期值,不是內(nèi)存值
next是修改的新值不是預(yù)期值
方法compareAndSet的源碼就可以看得出來(lái),里面注釋已經(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的操作是按照題主所說(shuō),用預(yù)期值和內(nèi)存值比較,只有當(dāng)相等時(shí),才會(huì)把新值寫(xiě)入,否則會(huì)不斷重試,是一種樂(lè)觀的態(tài)度,而真正的內(nèi)存值其實(shí)是AtomicInteger.value這個(gè)屬性(其實(shí)最關(guān)鍵也不是這個(gè)屬性,只是個(gè)引用而已,真正的boss后面會(huì)提到),注意這個(gè)value的有關(guān)鍵字volatile修飾
private volatile int value;
所以這個(gè)value值其實(shí)是一個(gè)共享變量,代表著這個(gè)變量的可見(jiàn)性,也就是線程之間的可見(jiàn)性,
=======================話多隨便扯了哈可見(jiàn)性,不喜可以直接略過(guò)================================
簡(jiǎn)單點(diǎn)說(shuō),Java內(nèi)存模型規(guī)定了變量是存在主存中(類似物理內(nèi)存)的,各個(gè)線程都有自己的工作緩存,在對(duì)某個(gè)變量操作時(shí),不是直接修改主存中的值,而是在自己的工作緩存中執(zhí)行,最后在同步到主存中,并且線程相互之間的是不能訪問(wèn)對(duì)方的工作緩存的
這里說(shuō)到的可見(jiàn)性,就是指,線程在操作有關(guān)鍵字volatile修飾的變量時(shí),當(dāng)成功修改了這個(gè)變量并寫(xiě)入了主存,那么其他線程的工作緩存中的變量會(huì)失效,所以此時(shí)其他線程再次去讀取變量時(shí)會(huì)直接從主存中去讀,而不會(huì)再用自己工作緩存中的值了
==========================================扯完==============================================
剛才說(shuō)到AtomicInteger.value這個(gè)屬性對(duì)于數(shù)據(jù)本身而言,只是一個(gè)引用,在調(diào)用compareAndSet方法時(shí),可以注意到第二個(gè)參數(shù),valueOffset,其實(shí)這才是關(guān)鍵...真正的Boss,真正的內(nèi)存的值,因?yàn)樯婕暗皆趈ava語(yǔ)言里很少聽(tīng)到的一個(gè)詞,指針,這個(gè)valueOffset其實(shí)就是對(duì)象內(nèi)的偏移量啦,這才是真正的內(nèi)存值
(之所以這個(gè)方法compareAndSet里調(diào)用的是Unsafe類的方法,Unsafe這其實(shí)就是封裝了一些類似指針的操作,指針才不安全嘛)
相關(guān)文章:
1. 點(diǎn)擊頁(yè)面就自動(dòng)輸入到mysql.求解2. java - IDEA從SVN檢出項(xiàng)目 并在tomcat上運(yùn)行 求詳細(xì)流程3. JAX-RS,GlassFish,Eclipse。簡(jiǎn)單的Web服務(wù)不起作用4. java如何生成token?5. node.js - nodejs使用formidable上傳文件問(wèn)題6. node.js - 帶有node_modules目錄的項(xiàng)目,用phpstorm打開(kāi)速度極慢,怎么解決?7. linux - 新手-----nginx怎么配置請(qǐng)求轉(zhuǎn)發(fā)?8. java - 多叉樹(shù)求值,程序高手,算法高手看過(guò)來(lái)9. javascript - windos下第一次用Django無(wú)法正確創(chuàng)建工程目錄10. ubuntu為什么這個(gè)文件夾里面的文件都被鎖上了?
