Search code examples
javavolatilenon-volatile

Why the program without 'volatile' works as 'volatile'?


As typed below, the program has a shared var flag without volatile:

public class T {
    public static void main(String[] args) {
        TT jump = new TT(() -> {
            while (true) {
                if (TT.flag) {
                    System.out.println("jump");
                    break;
                }
            }
        });
        jump.start();
        new TT(() -> {
            TT.flag = true; // P1
            LocalDateTime t1 = LocalDateTime.now();
            while (true) {
                if (Duration.between(t1, LocalDateTime.now()).toMillis() > 100) {
                    break;
                }
            }
            System.out.println("flag");
        }).start();

    }

    static class TT extends Thread {
        public static boolean flag = false;
        public TT(Runnable o) {
            super(o);
        }
    }
}

The program always returns normally. So I believe the line of P1 ,where the flag was set to true, updated flag in other threads.

But why? flag is not volatile, why its value was updated immediately? Always!


Solution

  • But why? flag is not volatile, why its value was updated immediately? Always!

    You are simply lucky; or unlucky, depending upon your perspective. I tried this on Ideone, and found that it timed out rather than terminating normally.

    Remember: not being able to observe a concurrency bug is not the same as an absence of a concurrency bug.

    The most sure you can be about code is when you can prove, according to the specification, that there are no bugs. That doesn't mean that the code will then work correctly; it just means that the problems are in the JVM implementation.

    In particulary, you can't prove that this code will work correctly, because there is no happens-before relationship between the write to flag in the second thread, and the read in the first thread. Adding volatile creates this guarantee, because a volatile write happens before a volatile read.

    That's not to say it will never work without volatile, it's just not guaranteed: a JVM only has to flush a thread's cached values at least as often as the spec requires, but can do it more often, or indeed not cache values at all.