[英]memory visibility without synchronized or volatile
說不帶“ synchronized”或“ volatile”關鍵字,一個線程所做的更改將永遠不會被另一個線程(或確定性的)看到是正確的嗎? 我在多核平台上多次運行以下程序,結果卻有所不同。 有時程序永遠不會終止,這是預期的場景。 但有時會退出並顯示“ 1”。
JDK:jdk1.8.0_73
操作系統:CentOS Linux版本7.1.1503
public class VolatileTest implements Runnable {
private int i = 0;
public void run() {
i++;
i++;
}
public int get() {
return i;
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
VolatileTest volatileTest = new VolatileTest();
executorService.execute(volatileTest);
while (true) {
int i = volatileTest.get();
if (i % 2 != 0) { //
System.out.format("i: %s \n", i);
System.exit(0);
}
}
}
}
說不帶“ synchronized”或“ volatile”關鍵字,一個線程所做的更改將永遠不會被另一個(或不確定的)線程看到,這是正確的嗎?
正確的說法是,如果在從寫入事件到后續讀取事件的關系發生之前沒有發生任何事件 ,則未說明會發生什么。
更改可能是立即的,也可能是延遲的,或者可能永遠都不可見。
而且,更改可能會以意外的順序可見。
在您的示例中, i
變量可以有3個可能的值,並且main
線程將看到哪個變量是不確定的和不可預測的。 您觀察到的行為並不意外。
volatileTest.get()
的輸出可以為0, 1, or 2
因為沒有同步並且run方法不是原子的。 而且,每個i++
操作都不是原子的。
因此,兩種情況都適用:
i++
操作完成一次后,get的操作就完成了。 i++
指令均已完成,並且get()
返回2,從而陷入無限循環。 說不帶“ synchronized”或“ volatile”關鍵字,一個線程所做的更改將永遠不會被另一個(或不確定的)線程看到,這是正確的嗎?
這是不正確的,這個問題已經回答了( this )
運行方法不是原子/線程安全/同步的,因此,很容易理解賦值int i = volatileTest.get();
可以獲取0到2之間的值。要實現所需的功能,您應該獲得一個lock
並在兩次遞增后重新實現它,或者只需將關鍵字synchronized
到方法簽名即可。
如果沒有“ synchronized”或“ volatile”關鍵字,則一個線程所做的更改將永遠不會被另一個線程看到
這是不正確的。 可見性未定義,因為它取決於JRE線程緩存的實現。
executorService.execute(volatileTest);
我認為測試可見度的方法不是最好的。 Jusst搜索stackoverflow並且有多個示例(有些甚至更糟)
該代碼執行一次run()方法(並且僅執行一次),根據線程緩存和線程調度程序的不同,您將獲得一小段更改, i==1
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.