簡體   English   中英

內存可見性,無需同步或不穩定

[英]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++操作都不是原子的。

因此,兩種情況都適用:

  1. 退出打印1: i++操作完成一次后,get的操作就完成了。
  2. 兩條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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM