happens-before в Java: модель памяти простыми словами
Проблема: видимость и переупорядочивание
Компилятор, JIT и процессор могут переставлять операции и держать значения в кэшах/регистрах ради скорости. Внутри одного потока это незаметно. Но другой поток может увидеть изменения «не в том порядке» или не увидеть вовсе.
Что такое happens-before
happens-before — это отношение «гарантированно раньше и видимо»: если действие A happens-before B, то результат A виден в B, и компилятор не переставит их местами. Это не про физическое время — про гарантии видимости.
Аналогия: эстафета. Пока не передал палочку (не установил happens-before), следующий бегун не имеет права стартовать и видеть, что ты пробежал. Передача палочки — это volatile-запись/выход из synchronized.
Как установить happens-before
- volatile: запись в volatile happens-before последующего чтения этой переменной.
- synchronized: выход из блока (release lock) happens-before входа в блок по тому же монитору.
- final-поля: корректно опубликованный объект гарантирует видимость своих final-полей после конструктора.
- Thread.start() happens-before кода потока; код потока happens-before
join().
Без одного из этих «мостиков» никакой гарантии нет: цикл
while(!flag){} с обычным boolean flag может крутиться вечно, даже если другой поток выставил flag=true — изменение просто не станет видимым.Частые вопросы
— Что такое happens-before?
Гарантия, что результат одного действия виден другому и порядок не переставят. Устанавливается volatile/synchronized/final/start-join.
— Зачем volatile для флага остановки?
Чтобы запись флага в одном потоке стала видимой в цикле другого — без volatile изменение может «застрять» в кэше.