Ответ
Java Memory Model (JMM) — это формальная спецификация, которая определяет, как потоки взаимодействуют через общую память. Она гарантирует предсказуемое поведение многопоточных программ на разных архитектурах процессоров. Основные концепции:
-
Happens-before (Происходит-до): Фундаментальное отношение порядка. Если операция A happens-before операции B, то все изменения памяти, сделанные в A, видны для B.
- Правила: Запуск потока, захват/освобождение монитора (
synchronized), запись/чтениеvolatile, инициализация объекта.
- Правила: Запуск потока, захват/освобождение монитора (
-
Видимость (Visibility): Гарантирует, что изменения переменной, сделанные одним потоком, становятся видимыми другим потокам. Без синхронизации это не гарантируется из-за кэшей процессора.
-
Атомарность (Atomicity): Гарантирует, что операция выполняется как единое целое. В Java атомарны:
- Чтение/запись примитивов (кроме
longиdoubleбезvolatile). - Операции с
volatileпеременными. - Операции с классами из
java.util.concurrent.atomic.
- Чтение/запись примитивов (кроме
-
Переупорядочивание (Reordering): Компилятор и процессор могут оптимизировать код, меняя порядок инструкций, если это не нарушает семантику в рамках одного потока. JMM определяет барьеры, которые ограничивают такое переупорядочивание между потоками.
Практические инструменты, обеспечивающие согласованность по JMM:
synchronizedблоки/методы: создают отношения happens-before и гарантируют атомарность блока.volatileпеременные: гарантируют видимость и запрещают переупорядочивание операций с ними.finalполя: гарантируют видимость корректно проинициализированного объекта после его конструирования.- Классы из
java.util.concurrent(AtomicInteger, ConcurrentHashMap и др.).
Пример проблемы видимости и её решения:
// ПРОБЛЕМА: Без синхронизации поток reader может никогда не увидеть флаг = true.
class Problem {
boolean flag = false; // НЕ volatile
void writer() { flag = true; }
void reader() { while (!flag) { /* бесконечный цикл */ } }
}
// РЕШЕНИЕ 1: Использование volatile
class Solution1 {
volatile boolean flag = false; // Гарантирует видимость и happens-before
}
// РЕШЕНИЕ 2: Использование synchronized
class Solution2 {
boolean flag = false;
synchronized void writer() { flag = true; }
synchronized boolean reader() { return flag; }
}