Volatile variable and non volatile reordering / visibility

拥有回忆 提交于 2019-12-03 22:28:11

is it correct to assume that the write to "text" by Thread writer is guaranteed to be visible by any other thread that reads it?

No. But it's guaranteed to be visible by any other thread that reads a before reading text, as your example does:

  • the write of text happens-before the write to a in the writer thread
  • the write of a in writer happens-before the read of a in the main thread
  • the happens-before relation is transitive
  • hence the the write of text happens before the read of a.
Tagir Valeev

No, it's not guaranteed, because the "flushing" is not that simple. Even if you actually write non-volatile something into the "main memory", it does not guarantee that consequent reads in other threads will read it from that main memory. Consider the following example:

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);
    }
}

There are quite good chances that waitForText will never finish, just because JIT-compiler will optimize it and move the reading of the vm.text out of the loop (as it's not volatile, no volatile reads are performed in the loop and text never changes inside the loop) making the loop infinite.

Volatile read/write not only affects the memory commitment, but also changes the JIT-compilation strategy. Add reading of vm.a in the while-loop and the program will work correctly.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!