【问题标题】:Why the program without 'volatile' works as 'volatile'?为什么没有“volatile”的程序会像“volatile”一样工作?
【发布时间】:2019-10-11 04:49:18
【问题描述】:

如下所示,该程序有一个共享 var 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 不是易失性的,为什么它的值会立即更新?永远!

【问题讨论】:

  • "Always" 除非您在所有兼容的 JVM 上对此进行了测试,否则您不能做出这样的声明。您正在尝试的 JVM 可能恰好被实现,所以这 happens 是真的。
  • 顺便说一句,it times out on Ideone

标签: java volatile non-volatile


【解决方案1】:

但是为什么呢? flag 不是 volatile,为什么它的值会立即更新?永远!

你很幸运;或不幸,取决于你的观点。我在 Ideone 上试了一下,发现是超时而不是正常终止。

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

您对代码最有把握的是,您可以根据规范证明没有错误。这并不意味着代码将正常工作。这只是意味着问题出在JVM实现中。

特别是,您无法证明这段代码可以正常工作,因为在第二个线程中对flag 的写入与在第一个线程。添加 volatile 会产生这种保证,因为 volatile 写入发生在 volatile 读取之前。

这并不是说它永远不会在没有 volatile 的情况下工作,只是不能保证:JVM 只需至少按照规范要求的频率刷新线程的缓存值,但可以做得更多通常,或者根本不缓存值。

【讨论】:

    猜你喜欢
    • 2019-06-10
    • 2014-03-03
    • 1970-01-01
    • 1970-01-01
    • 2015-09-06
    • 2019-07-20
    • 1970-01-01
    • 2019-01-19
    • 1970-01-01
    相关资源
    最近更新 更多