В Java, если переменная не помечена как volatile, будут ли её изменения гарантированно видны другим потокам?

«В Java, если переменная не помечена как volatile, будут ли её изменения гарантированно видны другим потокам?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Нет, без volatile (или других механизмов синхронизации) видимость изменений между потоками не гарантируется. JVM и процессор могут кэшировать значение переменной в регистрах или локальной памяти потока для оптимизации.

Почему это происходит: Без volatile, synchronized или атомарных классов (AtomicInteger и т.д.) нет happens-before отношения, обеспечивающего, что запись в одном потоке будет видна чтению в другом.

Пример проблемы:

public class VisibilityProblem {
    // Без volatile - изменение может быть не видно
    boolean flag = false;

    void writerThread() {
        flag = true; // Запись может остаться в кэше потока
    }

    void readerThread() {
        while (!flag) { // Может читать закэшированное старое значение (false)
            // Бесконечный цикл
        }
        System.out.println("Flag is now true");
    }
}

Решение:

  • Добавить модификатор volatile к переменной flag.
  • Использовать синхронизацию (synchronized блоки).
  • Использовать атомарные классы из java.util.concurrent.atomic.