Видимость разделяемых переменных Java

Как я понял из статьи «Параллелизм Java на практике», когда один поток изменяет какое-либо значение совместно используемой переменной, нет гарантии, что второй поток увидит это новое значение, если только он не использует ту же блокировку, что и первый поток, перед чтением. (стр. 37, рис. 3.1). Я провел небольшой тест и обнаружил, что каждый раз, когда я меняю какое-то значение var в одном потоке, его видит второй всегда! Без какой-либо синхронизации. Что я ошибаюсь?

Мой код:

public class Application {
    public int a = 5;
    public int b = 3;

    public static void main(String[] args) throws InterruptedException {
        final Application app = new Application();

        for (int i = 0; i < 20000; i++) {
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    app.a = 0;
                    app.b = 0;
                }
            });
            t.start();
            t.join();

            if (app.a == 5 || app.b==3) System.out.println("Old value!");
            app.a = 5;
            app.b = 3;
        }
    }
}

«Существует без гарантии, что другие потоки будут видят значение» - это не то же самое утверждение, что и «существует гарантия, что другие потоки не будет видят значение». Они могут или не могут, в зависимости от вашей реализации JVM, вашего процессора и положения Венеры по отношению к Сатурну.

Thomas 11.03.2018 17:44

Что-то о том, как вы проводите этот тест пахнет. Я не уверен, что вы тестируете то, что думаете о себе.

Makoto 11.03.2018 17:45

1. Вы вызываете join (), который обеспечивает гарантии видимости. Вам нужно попробовать читать, пока поток работает. Не после того, как вы к нему присоединились. Но в любом случае ваша логика ошибочна. Это в основном похоже на «Мне сказали, что ты можешь умереть, если перейдешь дорогу, не посмотрев сначала на машины. Но я делал это 10 раз, и я все еще жив».

JB Nizet 11.03.2018 17:45

Вы присоединились к потоку записи перед чтением переменных, что AFAIK создает барьер памяти с гарантиями видимости.

E_net4 the downvoter 11.03.2018 17:46
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
4
25
0

Другие вопросы по теме