關(guān)于線程的可見性
什么是線程間的可見性?
一個(gè)線程對共享變量值的修改,能夠及時(shí)的被其他線程看到惑灵。
什么是共享變量惫确?
如果一個(gè)變量在多個(gè)線程的工作內(nèi)存中都存在副本手报,那么這個(gè)變量就是這幾個(gè)線程的共享變量。
什么是java內(nèi)存模型改化?(Java Memory Model掩蛤,簡稱JMM)
JMM描述了java程序中各種變量(線程共享變量)的訪問規(guī)則,以及在JVM中將變量存儲(chǔ)到內(nèi)存和從內(nèi)存中讀取出變量這樣的底層細(xì)節(jié)陈肛。
- 規(guī)則1:
1>所有的變量都存儲(chǔ)在主內(nèi)存中
2>每個(gè)線程都有自己獨(dú)立的工作內(nèi)存揍鸟,里面保存該線程使用到的變量的副本(主內(nèi)存中該變量的一份拷貝)- 規(guī)則2:
1>線程對共享變量的所有操作都必須在自己的工作內(nèi)存中進(jìn)行,不能直接從主內(nèi)存中讀寫
2>不同線程之間無法直接訪問其他線程工作內(nèi)存中的變量句旱,線程間變量的傳遞需要通過主內(nèi)存來完成
示例代碼
public class VisableDemo {
//volatile 解決可見性問題
public volatile static boolean stop = false;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
int i = 0;
while (!stop){
i++;
}
System.out.println("result:"+i);
});
thread.start();
System.out.println("begin start thread");
Thread.sleep(10000);
stop = true;
}
}
Lock指令的作用:
- 將當(dāng)前處理器緩存行的數(shù)據(jù)寫回到系統(tǒng)內(nèi)存
- 這個(gè)寫回內(nèi)存的操作會(huì)使在其他cpu里緩存了該內(nèi)存地址的數(shù)據(jù)無效
什么時(shí)候需要用volatile阳藻?
當(dāng)存在多個(gè)線程對同一個(gè)共享變量進(jìn)行修改的時(shí)候,需要增加volatile谈撒,保證數(shù)據(jù)修改的實(shí)時(shí)可見腥泥。
指令重排序會(huì)導(dǎo)致運(yùn)行順序發(fā)生變化,如下圖:
image.png
這兩個(gè)方法運(yùn)行順序有可能不是順序進(jìn)行的港华,有可能會(huì)發(fā)生exeToCPU1()先執(zhí)行道川,造成了value的值計(jì)算出現(xiàn)差錯(cuò)。
為了避免這種問題出現(xiàn)立宜,cup層面做了處理:
- Store Barrier :強(qiáng)制所有在store屏障指令之前的store指令冒萄,都在該store屏障指令執(zhí)行之前被執(zhí)行,并把store緩沖區(qū)的數(shù)據(jù)都刷到CPU緩存
- Load Barrier :強(qiáng)制所有在load屏障指令之后的load指令橙数,都在該load屏障指令執(zhí)行之后被執(zhí)行尊流,并且一直等到load緩沖區(qū)被該CPU讀完才能執(zhí)行之后的load指令
- Full Barrier :復(fù)合了load和store屏障的功能
內(nèi)存屏障
image.png