面試官問你 知道什麼是ABA問題嗎?

2021-10-13 03:10:31 字數 4531 閱讀 8151

在開始問題闡述之前呢,我們先看一則小故事:

在開始問題的闡述之前,我們先來看一則小故事:

北宋宋真宗皇后死後,當時他的兩位愛妃劉妃和李妃都懷了孕,很顯然,誰生了兒子,誰就有可能立為正宮。劉妃久懷嫉妒之心,唯恐李妃生了兒子被立為皇后,於是與宮中總管都堂郭槐定計,在接生婆尤氏的配合下,乘李妃分娩時由於血暈而人事不知之機,將一狸貓剝去皮毛,血淋淋,光油油地換走了剛出世的太子。劉妃命宮女寇珠勒死太子,寇珠於心不忍,暗中將太子交付宦官陳琳,陳琳將太子裝在提盒中送至八賢王處撫養。再說真宗看到被剝了皮的狸貓,以為李妃產下了乙個妖物,乃將其貶入冷宮。不久,劉妃臨產,生了個兒子,被立為太子,劉妃也被冊立為皇后。誰知六年後,劉後之子病夭。真宗再無子嗣,就將其皇兄八賢王之子(實為當年被換走的皇子)收為義子,並立為太子。

從這故事看出來,太子出生被被換成了狸貓,最後陰差陽錯又回歸成為太子。雖然結果是一樣的,但是過程曲折了,太子真的是命途多舛啊。

為什麼說這個故事?其實跟我們今天要介紹的問題有很大的關係。同樣的結果,可能中間不知道發生了多少次操作,那麼我們能認為他沒變嗎?在不同的業務場景下,我們要仔細考慮這個問題。

在多執行緒場景下cas會出現aba問題,關於aba問題這裡簡單科普下,例如有2個執行緒同時對同乙個值(初始值為a)進行cas操作,這三個執行緒如下:

執行緒1,期望值為a,欲更新的值為b

執行緒2,期望值為a,欲更新的值為b

執行緒1搶先獲得cpu時間片,而執行緒2因為其他原因阻塞了,執行緒1取值與期望的a值比較,發現相等然後將值更新為b,然後這個時候出現了執行緒3,期望值為b,欲更新的值為a,執行緒3取值與期望的值b比較,發現相等則將值更新為a,此時執行緒2從阻塞中恢復,並且獲得了cpu時間片,這時候執行緒2取值與期望的值a比較,發現相等則將值更新為b,雖然執行緒2也完成了操作,但是執行緒2並不知道值已經經過了a->b->a的變化過程。

小明在提款機,提取了50元,因為提款機問題,有兩個執行緒,同時把餘額從100變為50:

此時可以看到,實際餘額應該為100(100-50+50),但是實際上變為了50(100-50+50-50)這就是aba問題帶來錯誤提交結果。

要解決aba問題,可以增加乙個版本號,當記憶體位置v的值每次被修改後,版本號都加1。

private

static atomicstampedreference

atomicstampedreference =

newatomicstampedreference

(100,1

);public

static

void

main

(string[

] args)

catch

(interruptedexception e)

atomicstampedreference.

compareandset

(100

,101

,atomicstampedreference.

getstamp()

,atomicstampedreference.

getstamp()

+1);

atomicstampedreference.

compareandset

(101

,100

,atomicstampedreference.

getstamp()

,atomicstampedreference.

getstamp()

+1);

},"t1").

start()

;// 第二個執行緒

newthread((

)->

catch

(interruptedexception e)

system.out.

println

("最新版本號:"

+ atomicstampedreference.

getstamp()

);system.out.

println

(atomicstampedreference.

compareandset

(100

,2019

,stamp,atomicstampedreference.

getstamp()

+1)+

"\t當前值:"

+ atomicstampedreference.

getreference()

);},

"t2").

start()

;}

1、初始值100,初始版本號1

2、執行緒t1和t2拿到一樣的初始版本號

3、執行緒t1完成aba操作,版本號遞增到3

4、執行緒t2完成cas操作,最新版本號已經變成3,跟執行緒t2之前拿到的版本號1不相等,操作失敗

執行結果:

t1拿到的初始版本號:1

t2拿到的初始版本號:1

最新版本號:3

false 當前值:100

atomicstampedreference可以給引用加上版本號,追蹤引用的整個變化過程,如:a -> b -> c -> d -> a,通過atomicstampedreference,我們可以知道,引用變數中途被更改了3次。

但是,有時候,我們並不關心引用變數更改了幾次,只是單純的關心是否更改過,所以就有了atomicmarkablereference

atomicmarkablereference的唯一區別就是不再用int標識引用,而是使用boolean變數——表示引用變數是否被更改過。

private

static atomicmarkablereference

atomicmarkablereference =

newatomicmarkablereference

(100

,false);

public

static

void

main

(string[

] args)

catch

(interruptedexception e)

atomicmarkablereference.

compareandset

(100

,101

,atomicmarkablereference.

ismarked()

,true);

atomicmarkablereference.

compareandset

(101

,100

,atomicmarkablereference.

ismarked()

,true);

},"t1").

start()

;// 第二個執行緒

newthread((

)->

catch

(interruptedexception e)

system.out.

println

("是否更改過:"

+ atomicmarkablereference.

ismarked()

);system.out.

println

(atomicmarkablereference.

compareandset

(100

,2019

,ismarked,

true)+

"\t當前值:"

+ atomicmarkablereference.

getreference()

);},

"t2").

start()

;}

1、初始值100,初始版本號未被修改 false

2、執行緒t1和t2拿到一樣的初始版本號都未被修改 false

3、執行緒t1完成aba操作,版本號被修改 true

4、執行緒t2完成cas操作,版本號已經變成true,跟執行緒t2之前拿到的版本號false不相等,操作失敗

執行結果:

t1版本號是否被更改:false

t2版本號是否被更改:false

是否更改過:true

false 當前值:100

以上是本期關於cas領域的乙個經典aba問題的解析,不知道你在實際的工作中有沒有遇到過,但是在面試中這塊是併發知識考查的重點。如果你還沒接觸過此類的問題,我的建議是你自己將上面的**執行一下,結合理論去理解一下aba問題所帶來的問題以及如何解決他,這對你日後的開發工作也是有莫大的幫助的!

摘錄 面試官也許會這樣問你

回答樣本一 我對工資沒有硬性要求,我相信貴公司在處理我的問題上會友善合理。我注重的是找對工作機會,所以只要條件公平,我則不會計較太多。回答樣本二 我受過系統的軟體程式設計的訓練,不需要進行大量的培訓,而且我本人也對程式設計特別感興趣。因此,我希望公司能根據我的情況和市場標準的水平,給我合理的薪水。回...

面試官問題

解釋一些壓縮感知理論 壓縮感知是一種全新的訊號採集和恢復理論,它打破了傳統的奈奎斯特取樣定律,可以從更少的觀測訊號訊號中重建出高質量的原始訊號。其基本思想是,當訊號是稀疏或可壓縮時,我們可以通過乙個隨機測量矩陣將高維訊號投影到低維空間,再通過乙個求解優化問題高概率的恢復原始訊號。解釋一下壓縮感知磁共...

當面試官問 你還有什麼想問的嗎 時,應該問什麼

經常面試別人,聽到各種不同的版本,最後這個環節,hr很有心機的問出這個問題,每個人的反應都是不一樣的。先舉乙個差點要被錄取,回答完這個問題後直接送走的勵志故事,這位仁兄是這樣問的 公司加班嚴重嗎?加班費怎麼算,這個我覺得還是說明白好。耐心回答下 聽說網際網路公司現在流行境外旅遊的福利,咱們也是網際網...