Java Memory Model
Java Memory Model (JMM) определяет, какие записи один поток может наблюдать в другом и какие переупорядочивания допустимы. Это спецификация поведения операций, а не схема heap, stack или кэшей процессора. Runtime-память описана отдельно в Стек и куча в Java.
Три проблемы общего состояния
| Свойство | Вопрос |
|---|---|
| Атомарность | Может ли другой поток увидеть частично выполненную операцию? |
| Видимость | Когда запись одного потока станет доступна другому? |
| Порядок | Можно ли наблюдать операции в ином порядке? |
Чтение и запись обычной переменной сами по себе не создают межпоточной гарантии. Компилятор, JIT и процессор могут переупорядочивать действия, если поведение одного потока сохраняется.
final class Worker {
private int answer;
private volatile boolean ready;
void publish() {
answer = 42;
ready = true;
}
int await() {
while (!ready) Thread.onSpinWait();
return answer; // увидит 42 благодаря volatile-связи
}
}Запись ready = true имеет release-семантику, последующее чтение true —
acquire-семантику. Через отношение happens before видна и предшествующая
запись answer.
Data race
Data race существует, когда два потока обращаются к одной переменной, хотя бы одно обращение — запись, а действия не упорядочены happens-before. Программа без data races ведёт себя так, будто действия потоков образуют некоторое последовательное исполнение.
volatile обеспечивает видимость и порядок для конкретной переменной, но не
делает составную операцию атомарной. count++ остаётся чтением, сложением и
записью. Для него нужны блокировка или Atomic типы данных.
Safe publication
Объект безопасно публикуется через lock, volatile-ссылку, static initialization,
потокобезопасную коллекцию или другие happens-before границы. Для корректно
сконструированного объекта final-поля получают дополнительные гарантии, если
this не утёк из конструктора.
Вопросы для собеседования
- JMM описывает heap и stack? Нет, она задаёт допустимые наблюдения операций.
- Что такое data race? Конфликтующие обращения без happens-before.
- Делает ли volatile
i++атомарным? Нет. - Зачем safe publication? Чтобы другой поток увидел корректно сконструированное состояние.
- Может ли JIT менять порядок операций? Да, если не нарушает однопоточную семантику и ограничения JMM.
- Что даёт synchronization? Взаимное исключение плюс гарантии видимости через monitor happens-before.