淺談AtomicInteger實(shí)現(xiàn)原理

AtomicInteger位于java.util.concurrent.atomic包下沉颂,是對(duì)int的封裝条摸,提供原子性的訪問和更新操作,其原子性操作的實(shí)現(xiàn)是基于CAS铸屉。

1. CAS

CAS(compare-and-swap)直譯即比較并交換钉蒲,提供原子化的讀改寫能力,是Java 并發(fā)中所謂 lock-free 機(jī)制的基礎(chǔ)彻坛。
CAS的思想很簡單:三個(gè)參數(shù)顷啼,一個(gè)當(dāng)前內(nèi)存值V、舊的預(yù)期值A(chǔ)昌屉、即將更新的值B钙蒙,當(dāng)且僅當(dāng)預(yù)期值A(chǔ)和內(nèi)存值V相同時(shí),將內(nèi)存值修改為B并返回true怠益,否則什么都不做仪搔,并返回false。
可能會(huì)有面試官問 CAS 底層是如何實(shí)現(xiàn)的蜻牢,在JAVA中,CAS通過調(diào)用C++庫實(shí)現(xiàn)烤咧,由C++庫再去調(diào)用CPU指令集。不同體系結(jié)構(gòu)中抢呆,cpu指令還存在著明顯不同煮嫌。比如,x86 CPU 提供 cmpxchg 指令抱虐;而在精簡指令集的體系架構(gòu)中昌阿,(如“l(fā)oad and reserve”和“store conditional”)實(shí)現(xiàn)的,在大多數(shù)處理器上 CAS 都是個(gè)非常輕量級(jí)的操作恳邀,這也是其優(yōu)勢所在懦冰。

CAS的缺點(diǎn)有以下幾個(gè)方面:

  1. ABA問題
    如果某個(gè)線程在CAS操作時(shí)發(fā)現(xiàn),內(nèi)存值和預(yù)期值都是A谣沸,就能確定期間沒有線程對(duì)值進(jìn)行修改嗎刷钢?答案未必,如果期間發(fā)生了 A -> B -> A 的更新乳附,僅僅判斷數(shù)值是 A内地,可能導(dǎo)致不合理的修改操作。針對(duì)這種情況赋除,Java 提供了 AtomicStampedReference 工具類阱缓,通過為引用建立類似版本號(hào)(stamp)的方式,來保證 CAS 的正確性举农。
  2. 循環(huán)時(shí)間長開銷大
    CAS中使用的失敗重試機(jī)制荆针,隱藏著一個(gè)假設(shè),即競爭情況是短暫的。大多數(shù)應(yīng)用場景中航背,確實(shí)大部分重試只會(huì)發(fā)生一次就獲得了成功秸妥。但是總有意外情況,所以在有需要的時(shí)候沃粗,還是要考慮限制自旋的次數(shù),以免過度消耗 CPU键畴。
    3.只能保證一個(gè)共享變量的原子操作

2.AtomicInteger原理淺析

public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;

    // setup to use Unsafe.compareAndSwapInt for updates
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;

    static {
        try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

    private volatile int value;
}
  • 從 AtomicInteger 的內(nèi)部屬性可以看出最盅,它依賴于Unsafe 提供的一些底層能力,進(jìn)行底層操作起惕;如根據(jù)valueOffset代表的該變量值在內(nèi)存中的偏移地址涡贱,從而獲取數(shù)據(jù)的。
  • 變量value用volatile修飾惹想,保證了多線程之間的內(nèi)存可見性问词。

下面以getAndIncrement為例,說明其原子操作過程

   public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }
    //unsafe.getAndAddInt
    public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }
  • 假設(shè)線程1和線程2通過getIntVolatile拿到value的值都為1嘀粱,線程1被掛起激挪,線程2繼續(xù)執(zhí)行
  • 線程2在compareAndSwapInt操作中由于預(yù)期值和內(nèi)存值都為1,因此成功將內(nèi)存值更新為2
  • 線程1繼續(xù)執(zhí)行锋叨,在compareAndSwapInt操作中垄分,預(yù)期值是1,而當(dāng)前的內(nèi)存值為2娃磺,CAS操作失敗薄湿,什么都不做,返回false
  • 線程1重新通過getIntVolatile拿到最新的value為2偷卧,再進(jìn)行一次compareAndSwapInt操作豺瘤,這次操作成功,內(nèi)存值更新為3
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末听诸,一起剝皮案震驚了整個(gè)濱河市坐求,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蛇更,老刑警劉巖瞻赶,帶你破解...
    沈念sama閱讀 217,084評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異派任,居然都是意外死亡砸逊,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門掌逛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來师逸,“玉大人,你說我怎么就攤上這事豆混÷ㄏ瘢” “怎么了动知?”我有些...
    開封第一講書人閱讀 163,450評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長员辩。 經(jīng)常有香客問我盒粮,道長,這世上最難降的妖魔是什么奠滑? 我笑而不...
    開封第一講書人閱讀 58,322評(píng)論 1 293
  • 正文 為了忘掉前任丹皱,我火速辦了婚禮,結(jié)果婚禮上宋税,老公的妹妹穿的比我還像新娘摊崭。我一直安慰自己,他們只是感情好杰赛,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評(píng)論 6 390
  • 文/花漫 我一把揭開白布呢簸。 她就那樣靜靜地躺著,像睡著了一般乏屯。 火紅的嫁衣襯著肌膚如雪根时。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評(píng)論 1 300
  • 那天辰晕,我揣著相機(jī)與錄音啸箫,去河邊找鬼。 笑死伞芹,一個(gè)胖子當(dāng)著我的面吹牛忘苛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播唱较,決...
    沈念sama閱讀 40,126評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼扎唾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了南缓?” 一聲冷哼從身側(cè)響起胸遇,我...
    開封第一講書人閱讀 38,980評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎汉形,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體概疆,經(jīng)...
    沈念sama閱讀 45,414評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡逗威,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了岔冀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凯旭。...
    茶點(diǎn)故事閱讀 39,773評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出罐呼,到底是詐尸還是另有隱情鞠柄,我是刑警寧澤,帶...
    沈念sama閱讀 35,470評(píng)論 5 344
  • 正文 年R本政府宣布嫉柴,位于F島的核電站厌杜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏计螺。R本人自食惡果不足惜期奔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望危尿。 院中可真熱鬧,春花似錦馁痴、人聲如沸谊娇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽济欢。三九已至,卻和暖如春小渊,著一層夾襖步出監(jiān)牢的瞬間法褥,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評(píng)論 1 269
  • 我被黑心中介騙來泰國打工酬屉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留半等,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,865評(píng)論 2 370
  • 正文 我出身青樓呐萨,卻偏偏與公主長得像杀饵,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子谬擦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評(píng)論 2 354

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