
概要:5 Happens-before、6有序性?
阻止(偽)編譯器認(rèn)為的無法“被代碼本身”改變代碼(變量/對象)進(jìn)行優(yōu)化。
?JDK1.2 前,Java內(nèi)存模型實(shí)現(xiàn)總是從主存(即共享內(nèi)存)讀取變量。當(dāng)前內(nèi)存模型,線程可以把變量保存本地內(nèi)存(機(jī)器寄存器),不直接在主存中讀寫。線程主存中修改,另一個線程繼續(xù)用寄存器中值(拷貝),造成數(shù)據(jù)的不一致。?

解決:變量聲明為?volatile,指示 JVM,這個變量不穩(wěn)定,每次使用它到主存中讀取。?

二 volatile關(guān)鍵字的可見性
volatile 修飾的變量,強(qiáng)迫從主存中讀寫,不同線程看到變量同一個值,保證可見性。

isRunning變量沒有加上volatile關(guān)鍵字時,死循環(huán),isRunning被修改但是沒有被寫到主存中,線程本地內(nèi)存中一直為true


while里加輸出或sleep死循環(huán)也會停,不管是否volatile關(guān)鍵字。

JVM會盡力保證內(nèi)存的可見性,只要CPU有時間,JVM會盡力去保證變量值的更新。
不同,volatile強(qiáng)制保證可見性。CPU占用,JVM不強(qiáng)制CPU去取最新值。加輸出或sleep后,有時間去保證內(nèi)存可見性
三 無法保證對變量原子性
自增操作(非原子操作)上不保證(個人感覺有問題)


運(yùn)行結(jié)果:上面的“count=i;”是一個原子操作,大部分都是正確結(jié)果99,也有部分不是99的結(jié)果。?

解決辦法:
使用synchronized關(guān)鍵字加鎖。(這只是一種方法,Lock和AtomicInteger原子類都可以)

四 synchronized關(guān)鍵字和volatile關(guān)鍵字比較
1.volatile輕量級,性能好;只用于變量;不會阻塞
synchronized可方法、代碼塊。會阻塞;1.6后效提升,實(shí)際用的多。
2.volatile解決可見性,不能保原子性。synchronized解決同步性,都能保證。
五、Happens-before
A Happens-before B:A對B可見。Happens-before原則:
1)順序規(guī)則:線程中,按照控制流順序,前面Happens-Before后續(xù)
2)volatile變量規(guī)則:volatile寫操作Happens-Before于后續(xù)讀操作(時間上)
3)傳遞性規(guī)則:A Happens-Before B 且 B Happens-Before C,那么A Happens-Before C
4)鎖的規(guī)則:解鎖Happens-Before于后續(xù)加鎖。(時間上)
5)線程start()規(guī)則:主線程A啟動B start(),start() Happens-Before B任意操作
6)線程join()規(guī)則:主線程A等待子線程B完成(主線程A調(diào)用子線程B的join()方法),當(dāng)子線程B完成后,主線程能夠看到子線程的操作(指的是對共享變量的操作)。
7)線程中斷規(guī)則:對線程interrupt()方法的調(diào)用先行發(fā)生與被中斷線程代碼檢測到中斷事件的發(fā)生,可以通過Thread.interrupted()檢測是否發(fā)生中斷。
8)對象終結(jié)規(guī)則:一個對象的初始化的完成,也就是構(gòu)造函數(shù)執(zhí)行的結(jié)束一定Happens-Before它的finalize()方法。
ps:與時間先后順序沒關(guān)系,以Happens-Before原則為準(zhǔn)
六、volatile解決有序性問題
依賴Happens-before前3條規(guī)則。A先于B,A對B可見

x(沒有volatile)有沒有可能等于0,因?yàn)?b>編譯優(yōu)化帶來指令重排,導(dǎo)致v = true 先于x = 42執(zhí)行,reader()正好在兩者之間執(zhí)行,用volatile修飾后,再分析:
1、先看Happens-Before第二條(寫先于讀),賦值判斷,writer()對v賦值,reader()判斷v值true后,說明v寫先讀。
2、結(jié)合Happens-Before第一條,可以得出
????????x = 42 Happens-Before v = true
????????v = true Happens-Before if(v)(判斷為true時)
????????if(v) Happens-Before System.out.println(x)
3、再結(jié)合Happens-Before第三條傳遞性,? x取值只能是42。
? ? ? ? x = 42 Happens-Before System.out.println(x)
https://blog.csdn.net/zcyt085/article/details/108309917