CAS:對(duì)于內(nèi)存中的某一個(gè)值V成玫,提供一個(gè)舊值A(chǔ)和一個(gè)新值B憋肖。如果提供的舊值V和A相等就把B寫入V萌衬。這個(gè)過(guò)程是原子性的。
CAS執(zhí)行結(jié)果要么成功要么失敗毕源,對(duì)于失敗的情形下一般采用不斷重試浪漠。或者放棄霎褐。
ABA:如果另一個(gè)線程修改V值假設(shè)原來(lái)是A址愿,先修改成B,再修改回成A冻璃。當(dāng)前線程的CAS操作無(wú)法分辨當(dāng)前V值是否發(fā)生過(guò)變化响谓。
關(guān)于ABA問(wèn)題我想了一個(gè)例子:在你非常渴的情況下你發(fā)現(xiàn)一個(gè)盛滿水的杯子俱饿,你一飲而盡歌粥。之后再給杯子里重新倒?jié)M水。然后你離開(kāi)拍埠,當(dāng)杯子的真正主人回來(lái)時(shí)看到杯子還是盛滿水,他當(dāng)然不知道是否被人喝完重新倒?jié)M土居。
解決這個(gè)問(wèn)題的方案的一個(gè)策略是每一次倒水假設(shè)有一個(gè)自動(dòng)記錄儀記錄下枣购,這樣主人回來(lái)就可以分辨在她離開(kāi)后是否發(fā)生過(guò)重新倒?jié)M的情況嬉探。這也是解決ABA問(wèn)題目前采用的策略。
ABA問(wèn)題是指在CAS操作中帶來(lái)的潛在問(wèn)題棉圈。
CAS意思是 compare and swap 或者 compare and set, 對(duì)于一個(gè)要更新的變量A涩堤,我們提供一個(gè)它的舊值a 和新值 b,如果變量A的值等于舊值 那么更新成功分瘾,否則失敗胎围。
如果CAS操作是基于CPU內(nèi)核的原子操作,那基本是不會(huì)出現(xiàn)ABA問(wèn)題的德召,但是如果CAS本身操作不滿足原子性白魂,則會(huì)帶來(lái)ABA問(wèn)題,
比如兩個(gè)線程
線程1 查詢A的值為a上岗,與舊值a比較福荸,
線程2 查詢A的值為a,與舊值a比較肴掷,相等敬锐,更新為b值
線程2 查詢A的值為b,與舊值b比較呆瞻,相等台夺,更新為a值
線程1 相等,更新B的值為c
可以看到這樣的情況下痴脾,線程1 可以正常 進(jìn)行CAS操作颤介,將值從a變?yōu)閏 但是在這之間,實(shí)際A值已經(jīng)發(fā)了a->b? b->a的轉(zhuǎn)換明郭。
仔細(xì)思考买窟,這樣可能帶來(lái)的問(wèn)題是,如果需要關(guān)注A值變化過(guò)程薯定,是會(huì)漏掉一段時(shí)間窗口的監(jiān)控
今天偶然看到一個(gè)ABA問(wèn)題可能帶來(lái)的問(wèn)題
小明在提款機(jī)始绍,提取了50元,因?yàn)樘峥顧C(jī)問(wèn)題话侄,有兩個(gè)線程亏推,同時(shí)把余額從100變?yōu)?0
線程1(提款機(jī)):獲取當(dāng)前值100,期望更新為50年堆,
線程2(提款機(jī)):獲取當(dāng)前值100吞杭,期望更新為50,
線程1成功執(zhí)行变丧,線程2某種原因block了芽狗,這時(shí),某人給小明匯款50
線程3(默認(rèn)):獲取當(dāng)前值50痒蓬,期望更新為100童擎,
這時(shí)候線程3成功執(zhí)行滴劲,余額變?yōu)?00,
線程2從Block中恢復(fù)顾复,獲取到的也是100班挖,compare之后,繼續(xù)更新余額為50P驹摇O糗健!
此時(shí)可以看到假丧,實(shí)際余額應(yīng)該為100(100-50+50)双揪,但是實(shí)際上變?yōu)榱?0(100-50+50-50)這就是ABA問(wèn)題帶來(lái)的成功提交