Ответ
Ключевое слово volatile решает две основные проблемы в многопоточном программировании:
- Проблема видимости (Memory Visibility): Без
volatileизменения переменной, сделанные одним потоком, могут быть не видны другим потокам из-за кеширования значений в регистрах процессора или локальной памяти потока. - Проблема переупорядочивания (Reordering): Компилятор и процессор могут переставлять инструкции для оптимизации.
volatileзапрещает переупорядочивание операций чтения/записи этой переменной с другими операциями, создавая барьер памяти.
Пример проблемы и решения:
// БЕЗ volatile (поток #2 может никогда не увидеть изменение flag)
class ProblemExample {
private boolean flag = false; // НЕ volatile
public void writer() { flag = true; } // Поток #1
public void reader() { while (!flag) { /* бесконечный цикл */ } } // Поток #2
}
// С volatile (гарантируется видимость изменений)
class SolutionExample {
private volatile boolean flag = false;
public void writer() { flag = true; } // Запись в volatile
public void reader() { while (!flag) { /* цикл завершится */ } } // Чтение volatile
}
Ключевые свойства и ограничения:
- Happens-before: Запись в
volatile-переменную происходит-до (happens-before) любого последующего чтения этой же переменной. - НЕ гарантирует атомарность:
volatileне делает составные операции (например,count++) атомарными. Для атомарных операций используйтеAtomicIntegerили синхронизацию. - Применение: Идеально подходит для флагов завершения, прерывания работы или однократной публикации неизменяемых объектов (safe publication).