Один поток в цикле читает обычное поле-флаг, другой его меняет, но цикл не завершается. Почему?
- Что делает volatile?
- Что такое проблема видимости в многопоточности?
- Чем volatile отличается от synchronized?
Проблема видимости: без синхронизации нет гарантии, что поток увидит изменение, сделанное другим, — нужен volatile или синхронизация.
- Компилятор и процессор вправе кэшировать значение и переупорядочивать операции
- volatile даёт видимость и порядок (happens-before), но не атомарность
count++
А ещё Для флага остановки volatile достаточно, для счётчика — нет
Подробно
Java Memory Model разрешает компилятору (в том числе JIT) и процессору оптимизации: держать значение поля в регистре или кэше ядра, переупорядочивать независимые операции. Для одного потока это незаметно, но другой поток может бесконечно читать старое значение. JIT вправе превратить while (!stop) {} в бесконечный цикл, прочитав stop один раз.
volatile на поле даёт две гарантии:
- видимость — запись сразу видна всем потокам, чтение всегда берёт актуальное значение;
- порядок — запись в volatile-поле «публикует» всё, что поток записал до неё: другой поток, прочитавший volatile, увидит и эти изменения (отношение happens-before).
Чего volatile не даёт — атомарности составных операций. count++ — это чтение, прибавление и запись; два потока всё равно потеряют обновление. Для этого нужны AtomicInteger или блокировка.
Типичное правильное применение volatile — флаг остановки, признак готовности, безопасная публикация неизменяемого объекта.
Пример
class Worker implements Runnable {
private volatile boolean stopped; // без volatile цикл может не завершиться
public void run() {
while (!stopped) { doWork(); }
}
public void stop() { stopped = true; }
}Что хотят услышать
- Причина: кэширование и переупорядочивание, нет гарантии видимости.
- Решение: volatile или синхронизация.
- Что даёт volatile (видимость, порядок) и чего не даёт (атомарность).
Частые ошибки
- Считать, что изменение поля всегда сразу видно другим потокам.
- Использовать volatile для счётчика и терять обновления.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗Поток с циклом имеет более высокий приоритет и не даёт записи выполниться
- ✗Изменение поля не успело записаться в память из-за задержки
- ✗Значение типа boolean нельзя менять из другого потока
- ✓Нет гарантии видимости — нужен volatile
Что спросят дальше
- Почему volatile не годится для счётчика?
- Какие ещё конструкции дают гарантию видимости?
Разбор темы
- Java Memory Model: happens-before и volatile
Зачем нужна модель памяти, видимость и переупорядочивание, отношение happens-before, семантика volatile и final, гонки данных.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.