Что такое отношение happens-before в Java Memory Model?

«Что такое отношение happens-before в Java Memory Model?» — вопрос из категории Java Core, который задают на 25% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Happens-before — это формальное отношение в Java Memory Model (JMM), которое гарантирует видимость и упорядоченность операций памяти между потоками. Если операция A happens-before операция B, то все изменения памяти, сделанные в A, будут видны потоку, выполняющему B.

Основные правила happens-before:

  1. Монитор (синхронизация): Освобождение монитора (выход из synchronized блока/метода) happens-before последующее захватывание того же монитора.
  2. Volatile переменные: Запись в volatile-поле happens-before каждое последующее чтение того же поля.
  3. Запуск потока: Вызов Thread.start() happens-before любые действия в запущенном потоке.
  4. Завершение потока: Все действия в потоке happen-before возврат из Thread.join() для этого потока.
  5. Инициализация объекта: Завершение конструктора объекта happens-before начало любого финализатора (finalize) для этого объекта.

Практический пример с volatile:

public class VisibilityExample {
    private volatile boolean ready = false;
    private int data = 0;

    void writer() {
        data = 42;          // (1)
        ready = true;       // (2) volatile запись
    }

    void reader() {
        if (ready) {        // (3) volatile чтение
            // Гарантированно увидит data = 42, так как (1) happens-before (2),
            // а (2) happens-before (3) по правилу volatile.
            System.out.println(data);
        }
    }
}

Без volatile компилятор или процессор могли бы переупорядочить операции (1) и (2), и поток reader мог бы увидеть ready = true, но data = 0.