請看以下程式碼
public class TestVolatile {
public static void main(String[] args) throws InterruptedException {
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
Thread.sleep(1);
while(true){
if(td.isFlag()){
System.out.println("------------------");
break;
}
}
}
}
class ThreadDemo implements Runnable {
private boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
把Thread.sleep(1)
換成Thread.sleep(1000)
就能取得flag
修改後的值,即td .isFlag()
傳回true
。
雖然看了Java記憶體模型的概念,但我不知道該如何解釋這段程式碼,誰能解釋一下?
相關問題: Java多執行緒的工作記憶體是什麼?
你得先說說你的預期效果是啥?問問題想問清楚
這個期待是沒有規範支撐的。程式碼中沒有做任何能保證 "子執行緒寫 happen-before 主執行緒讀" 的事情。
sleep(1000)
後看到修改只是巧合,一個JVM如果在更久後才讓主線程看到,甚至永遠不讓主線程看到都不違反規範。你的程式應該是想測試
volatile
关键字的功能。但是 “把Thread.sleep(1)
换成Thread.sleep(1000)
就能获得预期效果” 这样做理解上是不对的。首先,程序中总共有两个线程,主线程(暂称 线程M)和
new Thread(td)
(暫稱 線程T)。當寫
Thread.sleep(1)
的时候,线程M 在 1ms 之后,便开始在while(true)
循环中检查td.isFlag()
的值,但是因為記憶體可見性的關係,線程M 並不能及時讀取 線程T 中 flag 的值,所以此時導致了死循環;當寫
的值設為Thread.sleep(1000)
的時候,M 在1000ms 之後,開始在while(true)
循環中檢查td.isFlag() code> 的值;但是T 在200ms 的時候,便將
Thread.sleep(1000)
的时候,M 在 1000ms 之后,开始在while(true)
循环中检查td.isFlag()
的值;但是 T 在 200ms 的时候,便将 flag 的值设为true
了,所以,M 在 1000ms 之后检测td.isFlag()
的值肯定是返回true
的,那么第一次判断便会返回true
,产生输出并跳出while(true)
flagtrue
了,所以,M 在1000ms 之後檢測td.isFlag()
的值肯定是回傳true
的,那麼第一次判斷便會回傳true
,產生輸出並跳出while(true)
迴圈。為了讓 執行緒M 及時讀取到 執行緒T 中 flag 的值,需要將 flag
關鍵字進行修飾:volatile
使用volatile
的修改,其他線程都立刻可見。關於 的使用,可以參考我的部落格:Java 多執行緒(6):volatile 關鍵字的使用🎜可以參考以下三個程式碼:
其中第一個和你的情況一樣,由於多執行緒的可見性問題,可能導致無限循環下去。
第二個是使用
synchronized
解決此問題,大多數工作場景用這個好synchronized
解决此问题,大多数工作场景用这个好第三个是使用
volatile
第三個是使用volatile
解決,但這個關鍵字只保證可見性,在實際場景中限制比較大,得慎用