Что делает ключевое слово volatile в Java?

Ответ

Ключевое слово volatile гарантирует видимость изменений переменной для всех потоков и запрещает переупорядочивание операций с ней.

Как это работает:

  • Видимость: Запись в volatile-переменную немедленно сбрасывается в основную память, а чтение — всегда происходит из неё, минуя кеш процессора.
  • Запрет переупорядочивания: Операции с volatile-переменной не могут быть переставлены компилятором или процессором относительно других операций, что обеспечивает happens-before гарантии.

Важное ограничение: volatile не обеспечивает атомарность составных операций (например, count++).

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

public class StoppableTask {
    private volatile boolean stopRequested = false;

    public void run() {
        while (!stopRequested) {
            // Выполняем работу
        }
    }

    public void requestStop() {
        stopRequested = true; // Изменение будет сразу видно потоку run()
    }
}

Типичные сценарии:

  • Флаги состояния (запуск/остановка).
  • Публикация результатов инициализации (safe publication).

Ответ 18+ 🔞

А, ну это про volatile! Давай разжую, как есть, без соплей. Это ж не просто слово, это, блядь, как красная тряпка для компилятора и процессора.

Представь, у тебя переменная. Обычная. Поток её в кеше своего ядра поменял, а другим потокам похуй — они в своём кеше старую версию видят. И начинается: «А у меня ноль!», «А у меня уже сто!», «Вы все ебланы, тут единица!». Пиздец бардак, а не многопоточность.

Так вот, volatile — это такой крик на всю деревню: «Слышь, падлы! Кто меня меняет — сразу в общую память пиши! А кто читает — сразу из общей памяти тащи! Никаких своих, сука, локальных копий!»

Что он реально делает, этот волатиль:

  • Видимость, ёпта: Записал значение — и сразу пиздуй в оперативку. Прочитал — сразу из оперативки. Никаких тебе кешей, обманов и «ой, я не видел».
  • Порядок, блядь: Компилятор и процессор — те ещё извращенцы, любят команды переставлять для «оптимизации». С volatile-переменной этот трюк не прокатывает. Операции с ней — как столбы забора: до неё всё, что должно было случиться, случится, и после неё — тоже по плану. Это и есть те самые happens-before гарантии, о которых умники говорят.

Но вот что он НЕ делает, и это важно, как собственное яйцо: volatileНЕ ДЕЛАЕТ операции атомарными. Это пиздец как важно понять. Вот смотри, count++. Это же три операции, блядь: прочитать, увеличить, записать. Два потока могут вклиниться друг другу в этот момент, и в итоге оба увеличения пропадут. volatile тут нихуя не поможет, он только гарантирует, что они будут читать-писать из общей памяти, но перехлёст — запросто. Для этого нужен уже synchronized или атомики.

Где его, этого волатиля, применять? Да там, где просто и понятно!

Классика жанра — флаг остановки. Вот смотри, красота же:

public class StoppableTask {
    // Вот она, звезда! Помечаем volatile
    private volatile boolean stopRequested = false;

    public void run() {
        // Читаем из общей памяти. Как только другой поток впендюрит true — сразу увидим.
        while (!stopRequested) {
            // Делаем полезную хуйню
        }
        System.out.println("Ну всё, пиздуй на покой.");
    }

    public void requestStop() {
        // Пишем в общую память. Поток run() это гарантированно увидит.
        stopRequested = true;
    }
}

Без volatile поток run() мог бы закешировать значение false у себя в ядре и гонять вечно, даже когда requestStop() уже давно сказал true. А так — чётко, ясно, работает.

Короче, типичные сценарии:

  • Флаги (типа «работаем/стопимся»). Самый частый и правильный случай.
  • Публикация готового объекта. Инициализировал ты, скажем, конфиг в одном потоке (заполнил все поля), а потом записал ссылку на него в volatile-поле. Другие потоки, когда увидят эту ссылку не-null, увидят и всё, что внутри, уже проинициализированным. Это и есть safe publication.

Вот и вся магия. Не серебряная пуля, а точный инструмент. Используй там, где надо просто и чётко сигналить между потоками, а не строить сложные хуйни с общим доступом. Для сложного — другие инструменты, там свой цирк.