Какие механизмы в Java обеспечивают отношение happens-before?

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

Ответ

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

Основные правила и механизмы:

  1. Правило монитора (связь с synchronized): Освобождение монитора (выход из synchronized-блока) happens-before последующее захват того же монитора.

    // Поток 1
    synchronized (lock) {
        sharedFlag = true; // (1)
    } // Освобождение lock -> happens-before
    // Поток 2
    synchronized (lock) { // Захват того же lock
        if (sharedFlag) { // Гарантированно увидит true из (1)
            // ...
        }
    }
  2. Правило volatile: Запись в volatile-переменную happens-before каждое последующее чтение той же переменной.

    volatile boolean initialized = false;
    // Поток 1
    config = loadConfig(); // (2)
    initialized = true; // Запись в volatile
    // Поток 2
    if (initialized) { // Чтение volatile
        // Гарантированно увидит config, инициализированный в (2)
        use(config);
    }
  3. Правило Thread.start(): Вызов thread.start() happens-before начало выполнения любого кода в новом потоке.

  4. Правило Thread.join(): Все действия в потоке happen-before успешный возврат из join() для этого потока в другом потоке.

  5. Классы java.util.concurrent: Такие инструменты, как CountDownLatch.await(), CyclicBarrier.await(), получение результата из Future.get(), также устанавливают отношение happens-before.