面試官:volatile能不能不保證原子性?如何解決呢?
點(diǎn)擊上方“程序員大白”,選擇“星標(biāo)”公眾號(hào)
重磅干貨,第一時(shí)間送達(dá)
volatile不保證原子性
大廠面試題:
請(qǐng)你談?wù)剬?duì)volatile的理解? CAS你知道嗎? 原子類AtomicInteger的ABA問題談?wù)??原子更新引用知道嗎?/section> 我們都知道ArrayList是線程不安全的,請(qǐng)編碼寫一個(gè)不安全的案例并給出解決方案? 公平鎖/非公平鎖/可重入鎖/遞歸鎖/自旋鎖談?wù)勀愕睦斫???qǐng)手寫一個(gè)自旋鎖。 CountDownLatch、CyclicBarrier、Semaphore使用過嗎? 阻塞隊(duì)列知道嗎? 線程池用過嗎?ThreadPoolExecutor談?wù)勀愕睦斫猓?/section> 線程池用過嗎?生產(chǎn)上你是如何設(shè)置合理參數(shù)? 死鎖編碼及定位分析?
解析:
volatile為什么不保證原子性? 請(qǐng)你使用代碼驗(yàn)證volatile不保證原子性? 有什么辦法讓volatile保證原子性?
1、volatile不保證原子性代碼驗(yàn)證
public?class?VolatileAtomDemo?{undefined
????//?volatile不保證原子性
????//?原子性:保證數(shù)據(jù)一致性、完整性
????volatile?int?number?=?0;
????public?void?addPlusPlus()?{undefined
????????number++;
????}
????public?static?void?main(String[]?args)?{undefined
????????VolatileAtomDemo?volatileAtomDemo?=?new?VolatileAtomDemo();
????????for?(int?j?=?0;?j?20;?j++)?{
????????????new?Thread(()?->?{
????????????????for?(int?i?=?0;?i?1000;?i++)?{
????????????????????volatileAtomDemo.addPlusPlus();
????????????????}
????????????},?String.valueOf(j)).start();
????????}
????????//?后臺(tái)默認(rèn)兩個(gè)線程:一個(gè)是main線程,一個(gè)是gc線程
????????while?(Thread.activeCount()?>?2)?{undefined
????????????Thread.yield();
????????}
????????
????????//?如果volatile保證原子性的話,最終的結(jié)果應(yīng)該是20000
????????//?但是每次程序執(zhí)行結(jié)果都不等于20000
????????System.out.println(Thread.currentThread().getName()?+?"\tfinal?number?result?=?"?+?volatileAtomDemo.number);
????}
}
代碼執(zhí)行結(jié)果如下:多次執(zhí)行結(jié)果證明volatile不保證原子性


2、volatile不保證原子性原理分析
number++操作對(duì)應(yīng)的字節(jié)碼:

number++被拆分成3個(gè)指令
執(zhí)行GETFIELD拿到主內(nèi)存中的原始值number 執(zhí)行IADD進(jìn)行加1操作 執(zhí)行PUTFIELD把工作內(nèi)存中的值寫回主內(nèi)存中
當(dāng)多個(gè)線程并發(fā)執(zhí)行PUTFIELD指令的時(shí)候,會(huì)出現(xiàn)寫回主內(nèi)存覆蓋問題,所以才會(huì)導(dǎo)致最終結(jié)果不為20000,volatile不能保證原子性。

3、解決volatile不保證原子性問題
(1)方法前加synchronized解決
public?synchronized?void??addPlusPlus()?{
??number++;
}
(2)加鎖解決
//?使用鎖保證數(shù)據(jù)原子性
Lock?lock?=?new?ReentrantLock();
public?void?addPlusPlus()?{undefined
???lock.lock();
???number++;
???lock.unlock();
}
(3)原子類解決
//?使用原子類保證數(shù)據(jù)原子性
public?class?VolatileSolveAtomDemo?{
????//?原子Integer類型,保證原子性
????private?AtomicInteger?atomicNumber?=?new?AtomicInteger();
????//?底層通過CAS保證原子性
????public?void?addPlusPlus()?{undefined
????????atomicNumber.getAndIncrement();
????}
????public?static?void?main(String[]?args)?{
????????VolatileSolveAtomDemo?volatileSolveAtomDemo?=?new?VolatileSolveAtomDemo();
????????for?(int?j?=?0;?j?20;?j++)?{undefined
????????????new?Thread(()?->?{undefined
????????????????for?(int?i?=?0;?i?1000;?i++)?{undefined
????????????????????volatileSolveAtomDemo.addPlusPlus();
????????????????}
????????????},?String.valueOf(j)).start();
????????}
?????//?后臺(tái)默認(rèn)兩個(gè)線程:一個(gè)是main線程,一個(gè)是gc線程
?????while?(Thread.activeCount()?>?2)?{
??????????Thread.yield();
?????}
?????//?因?yàn)関olatile不保證原子性,所以選擇原子類AtomicInteger來解決volatile不保證原子性問題
?????//?最終每次程序執(zhí)行結(jié)果都等于20000
?????System.out.println(Thread.currentThread().getName()?+?"\tfinal?number?result?=?"?+?volatileSolveAtomDemo.atomicNumber.get());
????}
}
代碼執(zhí)行結(jié)果如下:多次執(zhí)行結(jié)果證明原子類是可以解決volatile不保證原子性問題

來源:blog.csdn.net/longgeqiaojie304/
article/details/89819093
推薦閱讀
關(guān)于程序員大白
程序員大白是一群哈工大,東北大學(xué),西湖大學(xué)和上海交通大學(xué)的碩士博士運(yùn)營(yíng)維護(hù)的號(hào),大家樂于分享高質(zhì)量文章,喜歡總結(jié)知識(shí),歡迎關(guān)注[程序員大白],大家一起學(xué)習(xí)進(jìn)步!
評(píng)論
圖片
表情


