簡體   English   中英

易失性變量和非易失性重新排序/可見性

[英]Volatile variable and non volatile reordering / visibility

因此,我以為我對這方面的知識已經足夠了解了,直到我讀了一些東西,使我懷疑我對此主題的了解。 我幾乎可以肯定這本書是不正確的,但也想問一下社區。

PS:尚未看到該書的勘誤表,因此很可能被公開為錯誤。

一個簡化的例子:

public class VolatileMain {

private volatile int a = 0;
private String text = "";

public static void main(String[] args) throws Exception {

    VolatileMain vm = new VolatileMain();

    Thread writer = new Thread() {

        @Override
        public void run() {
            System.out.println("Running thread " + Thread.currentThread().getName());
            vm.text = "hello world";
            vm.a = 5;
        }
    };

    writer.start();
    writer.join();

    System.out.println("Running thread " + Thread.currentThread().getName());
    System.out.println(vm.a);
    System.out.println(vm.text);

   }

}

因此,以給出的示例為前提,假設可以保證任何其他讀取該線程的線程都可以看到Thread writer對“文本”的寫入是否正確?

看來作者很支持變量“ a”的易變語義,並確保當刷新“ a”時也刷新對“ text”的寫操作,這是否可以保證?

我不認為是這樣,但是我自己的快速測試(上面)與此相反

你的意見。

假設由線程編寫器對“文本”的寫入保證可以被任何其他讀取它的線程可見,是否正確?

不會。但是可以保證任何其他讀取a線程在讀取text之前都可見,如您的示例所示:

  • 寫入text發生在寫入線程中寫入a之前
  • 的寫a在作家的之前發生的讀取a在主線程
  • 關系發生前的傳遞
  • 因此的寫text的讀取之前發生a

不,不能保證,因為“沖洗”不是那么簡單。 即使您實際上將非易失性內容寫入“主內存”,也不能保證其他線程的后續讀取操作也會從該主內存中讀取它。 考慮以下示例:

public class VolatileMain {

    private volatile int a = 0;
    private String text = "";

    public static void main(String[] args) throws Exception {

        VolatileMain vm = new VolatileMain();

        Thread writer = new Thread() {

            @Override
            public void run() {
                // Added sleep here, so waitForText method has chance to JIT-compile
                LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
                System.out.println("Running thread " + Thread.currentThread().getName());
                vm.text = "hello world";
                vm.a = 5;
                System.out.println("Text changed!");
            }
        };

        writer.start();

        waitForText(vm);

        writer.join();

        System.out.println("Running thread " + Thread.currentThread().getName());
        System.out.println(vm.a);
        System.out.println(vm.text);

    }

    // Wait for text change in the spin-loop
    private static void waitForText(VolatileMain vm) {
        int i = 0;
    /*
        @Edit by Soner
        Compiler may do following steps to optimize in lieu.
        String myCache = vm.text;
        -- Assume that here myCache is "" -- so stay forever.
        while (myCache.equals("")) { i++; }
    */
        while (vm.text.equals("")) {
            i++;
        }
        System.out.println("Wait complete: " + i);
    }
}

僅因為JIT編譯器會優化它並將vm.text的讀取移出循環(因為它不是易失性的,所以在循環中不執行易失性讀取並且text永遠不會更改), waitForText可能永遠不會完成在循環內)使循環無限。

易失的讀/寫操作不僅會影響內存分配,還會更改JIT編譯策略。 在while循環中添加vm.a讀取,程序將正常運行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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