java并發(fā)之CAS

寫(xiě)在最前面

在上文java并發(fā)之volatile末尾有提到张弛,volatile并不能保證++操作的線程安全鉴逞。我們來(lái)通過(guò)一個(gè)簡(jiǎn)單的例子看下為什么恶耽。

++測(cè)試demo

通過(guò)javap -v看下其反編譯后字節(jié)碼指令:
反編譯結(jié)果

從反編譯結(jié)果可以看出蛹含,++被拆成了這樣三個(gè)指令:

  1. getfield:獲取變量count中的值;

  2. iadd:進(jìn)行+1操作撒踪;

  3. putfield:將+1后的數(shù)據(jù)寫(xiě)回count过咬。

volatile雖然可以保證變量的可見(jiàn)性,但是并不能保證這三個(gè)操作的原子性制妄,所以它不能保證++操作的線程安全掸绞,那++操作的線程安全要怎么解決呢?

注:何謂原子性忍捡?
原子性是指一個(gè)操作不能被中斷集漾,即使是在多個(gè)線程一起執(zhí)行的時(shí)候,一旦開(kāi)始砸脊,也不會(huì)被其他線程打斷具篇。

  1. 第一種簡(jiǎn)單粗暴的方法就是加鎖了,但是這樣做開(kāi)銷(xiāo)有點(diǎn)大了耶凌埂;

  2. 第二種方法就是使用JDK的CAS了驱显,juc包下也有相關(guān)Atomic類可以支持,使用簡(jiǎn)單瞳抓,而且高效埃疫。(哈哈哈,終于繞回了本文的主題啊孩哑,不容易啊~~~)

接下來(lái)我們就通過(guò)分析CAS相關(guān)源碼實(shí)現(xiàn)來(lái)看看CAS是如何做到線程安全的栓霜。

CAS原理

CAS,Compare and swap横蜒,比較和替換胳蛮。CAS的操作包括三個(gè)參數(shù):內(nèi)存位置(V)、預(yù)期原值(A)和新的值(B)丛晌,如果V和A相同仅炊,處理器會(huì)將該位置的值修改為B,否則澎蛛,處理器不會(huì)做任何操作抚垄。

在前文java并發(fā)編程之原子類已經(jīng)詳細(xì)介紹了JDK提供的Atomic相關(guān)原子類的使用及實(shí)現(xiàn),它們的實(shí)現(xiàn)都很神似谋逻,都是通過(guò)Unsafe提供的compareAndSwap開(kāi)頭的方法來(lái)完成對(duì)value的并發(fā)修改的呆馁。接下來(lái)我們就以compareAndSwapInt方法為例來(lái)看看它到底是怎么保證并發(fā)修改的安全性。

compareAndSwapInt實(shí)現(xiàn)

compareAndSwapInt聲明

從聲明可以看出毁兆,compareAndSwapInt是一個(gè)native的方法智哀,該方法的實(shí)現(xiàn)位于unsafe.cpp中:

compareAndSwapInt實(shí)現(xiàn).png

從源碼可以看出,compareAndSwapInt主要做了這些事情:

  1. 獲取value在內(nèi)存中的地址荧恍;

  2. 調(diào)用Atomic::cmpxchg方法完成比較替換瓷叫,其中e是原始值屯吊,x是新的值。

接下來(lái)我們來(lái)看看Atomic::cmpxchg的相關(guān)實(shí)現(xiàn):

注:以linux x86平臺(tái)為例摹菠,具體實(shí)現(xiàn)在atomic_linux_x86.inline.hpp中

Atomic::cmpxchg實(shí)現(xiàn)

在開(kāi)始介紹源碼之前先科普下這里用到的內(nèi)嵌匯編的關(guān)鍵字:

  1. __asm__:用來(lái)聲明一個(gè)內(nèi)聯(lián)匯編表達(dá)式盒卸,任何一個(gè)內(nèi)聯(lián)匯編表達(dá)式都是以它開(kāi)頭的,是必不可少的次氨;

  2. __volatile__或者volatile__volatile__是GCC關(guān)鍵字volatile的宏定義蔽介,如果用了它,則是向GCC聲明不允許對(duì)該內(nèi)聯(lián)匯編優(yōu)化煮寡,否則當(dāng)使用了優(yōu)化選項(xiàng)(-O)進(jìn)行編譯時(shí)虹蓄,GCC將會(huì)根據(jù)自己的判斷決定是否將這個(gè)內(nèi)聯(lián)匯編表達(dá)式中的指令優(yōu)化掉。

有了這些科普我們?cè)賮?lái)看代碼是不是就和諧多了幸撕,Atomic::cmpxchg其實(shí)就做了這樣幾件事:

  • 判斷當(dāng)前系統(tǒng)是否是多核處理器薇组;

  • 依賴指令cmpxchg完成比較替換,如果當(dāng)前系統(tǒng)是多核處理器坐儿,將會(huì)在指令前加lock前綴律胀,否則不加。其中具體是否要加lock前綴的處理在宏LOCK_IF_MP中定義:

    LICK_IF_MP聲明

lock前綴保證了CAS并發(fā)操作的安全性貌矿。

注:在上文java并發(fā)之volatile中已經(jīng)詳細(xì)介紹過(guò)lock前綴的意義炭菌,在這里我就不再贅述了,有需要了解的小伙伴請(qǐng)自行移步啦~

CAS存在的問(wèn)題

CAS雖然可以很高效原子操作逛漫,但是它也是存在問(wèn)題的黑低。

  1. ABA問(wèn)題
    因?yàn)镃AS會(huì)在更新值的時(shí)候會(huì)檢查值有沒(méi)有發(fā)生改變,如果沒(méi)有發(fā)生改變就更新酌毡,否則不更新克握,但是如果一個(gè)值原來(lái)是A,變成了B阔馋,再變回A玛荞,這時(shí)候CAS進(jìn)行檢查時(shí)會(huì)誤認(rèn)為它沒(méi)有發(fā)生變化娇掏。針對(duì)這種情況呕寝,juc包提供了AtomicStampedReference,通過(guò)控制變量值的版本號(hào)來(lái)解決ABA問(wèn)題婴梧。

  2. 循環(huán)時(shí)間長(zhǎng)開(kāi)銷(xiāo)大
    自旋CAS如果長(zhǎng)時(shí)間不成功會(huì)給CPU帶來(lái)比較大的執(zhí)行開(kāi)銷(xiāo)下梢。

  3. 只能保證一個(gè)共享變量的原子操作
    對(duì)一個(gè)共享變量的操作,使用循環(huán)CAS肯定可以保證其原子性塞蹭,但是如果對(duì)多個(gè)變量操作時(shí)孽江,CAS就比較雞肋了。當(dāng)然有一個(gè)辦法就是把幾個(gè)共享變量合并成一個(gè)大的對(duì)象番电,然后CAS操作這個(gè)大對(duì)象岗屏。同樣辆琅,juc包也提供AtomicReference用于更新對(duì)象。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末这刷,一起剝皮案震驚了整個(gè)濱河市婉烟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌暇屋,老刑警劉巖似袁,帶你破解...
    沈念sama閱讀 221,406評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異咐刨,居然都是意外死亡昙衅,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)定鸟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)而涉,“玉大人,你說(shuō)我怎么就攤上這事仔粥∮て祝” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,815評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵躯泰,是天一觀的道長(zhǎng)谭羔。 經(jīng)常有香客問(wèn)我,道長(zhǎng)麦向,這世上最難降的妖魔是什么瘟裸? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,537評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮诵竭,結(jié)果婚禮上话告,老公的妹妹穿的比我還像新娘。我一直安慰自己卵慰,他們只是感情好沙郭,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,536評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著裳朋,像睡著了一般病线。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鲤嫡,一...
    開(kāi)封第一講書(shū)人閱讀 52,184評(píng)論 1 308
  • 那天送挑,我揣著相機(jī)與錄音,去河邊找鬼暖眼。 笑死惕耕,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的诫肠。 我是一名探鬼主播司澎,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼欺缘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了挤安?” 一聲冷哼從身側(cè)響起浪南,我...
    開(kāi)封第一講書(shū)人閱讀 39,668評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎漱受,沒(méi)想到半個(gè)月后络凿,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,212評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡昂羡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,299評(píng)論 3 340
  • 正文 我和宋清朗相戀三年絮记,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片虐先。...
    茶點(diǎn)故事閱讀 40,438評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡怨愤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蛹批,到底是詐尸還是另有隱情撰洗,我是刑警寧澤,帶...
    沈念sama閱讀 36,128評(píng)論 5 349
  • 正文 年R本政府宣布腐芍,位于F島的核電站差导,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏猪勇。R本人自食惡果不足惜设褐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,807評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望泣刹。 院中可真熱鬧助析,春花似錦、人聲如沸椅您。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,279評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)掀泳。三九已至雪隧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間开伏,已是汗流浹背膀跌。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,395評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工遭商, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留固灵,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,827評(píng)論 3 376
  • 正文 我出身青樓劫流,卻偏偏與公主長(zhǎng)得像巫玻,于是被迫代替她去往敵國(guó)和親丛忆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,446評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 高山流水仍秤,珠落玉盤(pán)熄诡。水帶麻山春,杯含清凈影诗力。 一粒粟中藏世界凰浮,半升鐺中煮山河。 寂寂麻山墓苇本,憑吊幾多人袜茧。瀟瀟雨,斜...
    jingtu閱讀 428評(píng)論 0 0