多執行緒變數同步機制
阿新 • • 發佈:2019-02-02
多執行緒中同一個變數會共享,但是有時候會發現不同執行緒中的共享變數,值不同步,原來每個執行緒都會有自己的記憶體存放變數的快取值,而不是一起使用主記憶體中的變數值。
問題:主執行緒的while迴圈中,當flag
為true時,迴圈體為空的話,後面的列印語句不會執行,會一直在while裡迴圈;
而在迴圈體中加上一句語句,比如System.out.println(),迴圈就會正常結束,執行後面的輸出語句。
為什麼當while迴圈體為空時不會退出迴圈,加入一句列印就會退出迴圈?
例如:
public class Test{
public static void main(String args[]){
R r=new R();
Thread t=new Thread(r);
t.start();
while(!r.flag ){
}
System.out.println("end");
}
}
class R implements Runnable{
public boolean flag=false;
public void run(){
int x=0;
while(x<1000){
x++;
System.out.println(x);
}
flag=true;
}
}
答:因為多執行緒之間不是絕對同步的。
在執行時為了提高效率會將資料載入到暫存器中,所以有時雖然記憶體中資料已經改變,但還未即時更新到暫存器中,就會出現不同步的情況。
R
flag
是從其工作記憶體取,主執行緒的while迴圈裡什麼都不寫,會導致呼叫訪問flag
太頻繁,導致主記憶體不會及時重新整理工作記憶體的flag
值,所以一直會訪問到flag
為false
,當加入System.out.println()
後,jvm的排程機制(會選擇在執行其他任務的時候同步flag)(訪問flag
有了明顯間隔),所以當加了一句列印語句之後,主記憶體就有空去重新整理到R
執行緒的工作記憶體,發現flag更新了,這樣才能正常退出while
迴圈。
volatile 關鍵字可以強制每次都從主記憶體中讀取,而不是用自己執行緒工作記憶體中的快取,這樣可以實現同步變數,但效率會低不少。
例如: