Что гарантирует ключевое слово volatile в Java?

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

Ответ

Ключевое слово volatile гарантирует две основные вещи в многопоточном контексте:

  1. Видимость (Visibility): Любое изменение значения volatile-переменной, сделанное одним потоком, немедленно становится видимым для всех других потоков. Без volatile изменения могут оставаться в кэше процессора потока и не быть видны другим.
  2. Запрет переупорядочивания (Prevention of Reordering): Операции чтения и записи volatile-переменной создают барьеры памяти. Это запрещает компилятору и процессору переставлять эти операции с другими операциями чтения/записи памяти, что сохраняет порядок, ожидаемый программистом.

Пример использования (флаг остановки):

public class WorkerThread implements Runnable {
    private volatile boolean running = true; // Гарантирует, что поток B увидит изменение из потока A

    public void run() {
        while (running) { // Чтение всегда актуального значения
            // выполнение работы
        }
    }

    public void stop() {
        running = false; // Запись видна всем потокам
    }
}

Чего volatile НЕ гарантирует:

  • Атомарность составных операций. Операция count++ (чтение-изменение-запись) не является атомарной, даже если count объявлен как volatile. Для атомарных операций используйте AtomicInteger или синхронизацию.
  • Взаимное исключение (mutual exclusion). volatile не заменяет synchronized.

Типичные сценарии: простые флаги состояния, однократная инициализация (шаблон Singleton с Double-Checked Locking).