我一直在試驗Java線程可見性問題,通過一個共享的布爾和非易失性變量向目標線程發送一個停止信號到線程的流行示例,目標線程似乎沒有得到它)如下圖所示:Java線程可視性和同步
public class ThreadVisibilityTest {
//Shared variable to send a signal to the thread
static boolean stopped = false;
public static void main(String[] args) throws Exception {
Thread targetThread = new Thread(new Runnable() {
public void run() {
while(!stopped) {}
System.out.println("Target thread gets signal and stops...");
}
});
targetThread.start();
TimeUnit.SECONDS.sleep(5);
stopped=true;
System.out.println("Main thread has sent stop signal to the thread...");
}
}
主線程設置stopped
爲true,目標線程無法得到它的手段在5秒後發出停止信號給目標線程,因此不會停止。
定義stopped
變量爲volatile
明顯解決了這個問題。
卜後來我意識到,如果我做stopped
變量non volatile
而是訪問它在目標線程背景,目標線程得到最終值和停止。所以線程可見性問題似乎可以像使用volatile
來解決。
Thread targetThread = new Thread(new Runnable() {
public void run() {
while(true) {
synchronized(this) {
if(stopped) break;
}
}
System.out.println("Target thread gets signal and stops...");
}
});
而且還可以用於同步的對象監視器似乎沒有任何效果如下:
synchronized(Thread.class) {
if(stopped) break;
}
這東西是偶然發生還是我錯過了什麼? 或者我們可以說通過互斥訪問共享變量似乎強制目標線程刷新其緩存內存,就像訪問變量volatile
一樣嗎?
如果後者是真實的你建議克服線程可見性問題,通過揮發性關鍵字或訪問互斥?
在此先感謝
如果您知道必須使用此變量的最新值,爲什麼您會選擇不使用易失性?你認爲它有什麼問題? –
如果你想使用同步,你當然必須做在相同的監視器上同步停止塊的寫入和讀取。您不會在同步塊中寫入該值。 –
我不是不想選擇易變的。我試圖理解爲什麼互斥也解決了內存可見性問題,因爲我已經測試並發現,通過互斥來訪問共享變量會使您像volatile一樣獲得最終值。 – Serdar