普通變量與JMM
- 對(duì)于普通變量,每個(gè)線程操作共享變量時(shí)男翰,會(huì)將這個(gè)變量從主內(nèi)存copy一份到自己的工作內(nèi)存
- 當(dāng)B線程對(duì)這個(gè)變量做修改時(shí),只是修改了自己工作內(nèi)存中的副本變量并更新到主內(nèi)存中纽乱,A線程工作內(nèi)存中的這個(gè)變量的值還是主內(nèi)存更新前的值
Volatile關(guān)鍵字
- Volatile是Java中與線程安全相關(guān)的關(guān)鍵字蛾绎,是一種輕量級(jí)鎖
- 用法:static volatile boolean flag = false;
- 特點(diǎn):
- 保證有序性:執(zhí)行到Volatile變量的讀寫(xiě)操作時(shí),在其前面的所有操作肯定已經(jīng)完成租冠,其后面的操作肯定還沒(méi)有進(jìn)行
- 保證可見(jiàn)性:一個(gè)線程修改了某個(gè)變量的值鹏倘,這個(gè)新值對(duì)其他線程來(lái)說(shuō)是立即可見(jiàn)的
- 不保證原子性:多個(gè)線程對(duì)變量的修改,會(huì)導(dǎo)致數(shù)據(jù)丟失
Volatile變量與JMM
-
保證可見(jiàn)性:
- 每個(gè)線程會(huì)將主內(nèi)存中的共享變量復(fù)制到自己的工作內(nèi)存中
- 當(dāng)B線程對(duì)這個(gè)變量做修改時(shí)顽爹,在修改了自己工作內(nèi)存中的副本變量后并更新到主內(nèi)存中
- 將新的的變量值在更新到主內(nèi)存的過(guò)程中纤泵,有store和write兩個(gè)過(guò)程
- 使用store將新值存儲(chǔ)到主內(nèi)存中時(shí),會(huì)經(jīng)過(guò)內(nèi)存總線镜粤,但是每個(gè)CPU會(huì)對(duì)總線有個(gè)監(jiān)控機(jī)制捏题,一旦嗅探到有改變主內(nèi)存中變量值時(shí),會(huì)將自己工作內(nèi)存中的這個(gè)變量副本值失效肉渴,A線程只能重新read主內(nèi)存中的這個(gè)變量公荧。
- 為了避免:在store之后write之前,A線程就讀取主內(nèi)存中的變量值(這時(shí)讀取的是write之前的值同规,是舊值)循狰。所以在匯編層面對(duì)store&write操作加了一把鎖,只有真正更新完主內(nèi)存中的變量值捻浦,其他線程才能讀取到正確的新值晤揣。
- 使得一個(gè)線程修改了變量值桥爽,其他線程能馬上讀取到最新的變量值朱灿,即:可見(jiàn)性
-
保證有序性:
- 當(dāng)程序執(zhí)行到Volatile變量的讀寫(xiě)操作時(shí),在其前面的操作的更改肯定全部已經(jīng)進(jìn)行钠四,且結(jié)果已經(jīng)對(duì)后面的操作可見(jiàn)盗扒;在其后面的操作肯定還沒(méi)有進(jìn)行
- 在進(jìn)行指令優(yōu)化時(shí),不能將在對(duì)Volatile變量訪問(wèn)的語(yǔ)句放在其后面執(zhí)行缀去,也不能把Volatile變量后面的語(yǔ)句放到其前面執(zhí)行
-
不保證原子性:
- 兩個(gè)線程同時(shí)完成賦值(assign)操作后侣灶,都會(huì)將新的值存儲(chǔ)(store)到主內(nèi)存再寫(xiě)入(write)主內(nèi)存中的共享變量
- 這里的store和write會(huì)在匯編層面加一把鎖,所以假設(shè)A線程在往主內(nèi)存store&write數(shù)據(jù)時(shí)缕碎,B線程無(wú)法向主內(nèi)存store&write操作
- 由于可見(jiàn)性褥影,此時(shí)的B線程還會(huì)嗅探到共享變量的變動(dòng),B線程會(huì)在第一時(shí)間將使自己工作內(nèi)存中的共享變量失效咏雌,這個(gè)失效抹去了B線程中之前的assign結(jié)果凡怎,即:對(duì)Volatile變量的操作無(wú)法保證原子性