Что такое volatile в Java и как он работает
Что проверяют
Понимаете ли вы разницу между видимостью и атомарностью. Это главный водораздел: volatile решает первое и не решает второе.
Как отвечать
volatile гарантирует две вещи:
- видимость: запись в поле сразу видна другим потокам, чтение всегда идёт из основной памяти, а не из кэша ядра;
- запрет переупорядочивания: операции до записи не переедут после неё (барьер памяти).
Чего он не даёт: атомарности составных операций. count++ это чтение, увеличение и запись, и два потока легко потеряют одно из увеличений даже на volatile.
Типичное применение это флаг остановки:
private volatile boolean running = true;
public void stop() { running = false; }
public void run() {
while (running) { doWork(); } // без volatile поток может не увидеть изменения никогда
}Для счётчиков нужны AtomicInteger или synchronized, для сложных инвариантов только блокировка.
Ещё volatile встречается в двойной проверке при ленивой инициализации: без него другой поток может увидеть ссылку на ещё не до конца сконструированный объект.
Где спотыкаются
Считают volatile заменой synchronized. Он не даёт взаимного исключения: критическую секцию им не защитить.
Не могут объяснить, почему цикл без volatile может не завершиться никогда: компилятор вправе поднять чтение поля из цикла, раз внутри оно не меняется.
Забывают, что на массиве volatile относится к самой ссылке, а не к элементам.