0

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

4

1 回答 1

1

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

你很幸运;或不幸,取决于你的观点。我在 Ideone 上试过这个,发现它超时而​​不是正常终止。

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

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

特别是,您无法证明此代码将正常工作,因为在第二个线程中的写入和第一个线程中的读取之间没有发生之前的关系。flag添加volatile创建此保证,因为易失性写入发生在易失性读取之前。

这并不是说没有 volatile 它将永远无法工作,只是不能保证:JVM 只需至少按照规范要求的频率刷新线程的缓存值,但可以更频繁地执行,或者根本不缓存值。

于 2019-10-11T07:54:51.340 回答