为什么没有“ volatile”的程序可以作为“ volatile”工作?

时间:2019-10-11 04:49:18

标签: java volatile non-volatile

如下所述,该程序具有一个共享变量flag,而没有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);
        }
    }
}

程序始终正常返回。因此,我相信P1行,其中flag设置为true,并在其他线程中更新了flag

但是为什么呢? flag不易变,为什么立即更新其值?总是!

1 个答案:

答案 0 :(得分:2)

  

但是为什么呢?标志不是易失的,为什么它的值会立即更新?总是!

您真是幸运;还是不幸,取决于您的观点。我在Ideone上进行了尝试,发现它超时而​​不是正常终止。

请记住:无法观察并发错误与没有并发错误是不同的。

最能确定代码的地方是根据规范可以证明没有错误。这并不意味着代码将正确运行;只是意味着问题出在JVM实现中。

尤其是,您无法证明此代码将正常运行,因为第二个线程对flag的写入与读取之间没有先于关系在第一个线程中。添加volatile会产生这种保证,因为易失性写入发生在易失性读取之前。

这并不是说它在没有volatile的情况下将永远无法工作,只是不能保证:JVM至少必须至少按规范要求的次数刷新线程的缓存值,但它可以执行更多操作经常,甚至根本不缓存值。