Почему программа без «volatile» работает как «volatile»? - PullRequest
1 голос
/ 11 октября 2019

Как указано ниже, программа имеет общую переменную 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 Ответ

2 голосов
/ 11 октября 2019

Но почему? Флаг не является изменчивым, поэтому его значение было обновлено немедленно? Всегда!

Вам просто повезло;или неудачно, в зависимости от вашей точки зрения. Я попробовал это на Ideone и обнаружил, что время ожидания истекло, а не завершилось нормально.

Помните: отсутствие возможности наблюдать ошибку параллелизма - это не то же самое, что отсутствие ошибки параллелизма.

Вы можете быть уверены в коде, когда в соответствии со спецификацией можете доказать, что ошибок нет. Это не значит, что код будет работать правильно;это просто означает, что проблемы в реализации JVM.

В частности, вы не можете доказать, что этот код будет работать правильно, потому что между 1011 * не существует отношения случай-до . flag во втором потоке, а чтение в первом. Добавление volatile создает эту гарантию, потому что энергозависимая запись происходит перед энергозависимым чтением.

Нельзя сказать, что никогда не будет работать без энергозависимой, просто это не гарантируется: JVM имеет толькоочищать кэшированные значения потока, по крайней мере, так часто, как этого требует спецификация, но может делать это чаще или вообще не кэшировать значения.

...