Ответ
Ключевое слово volatile решает проблемы видимости и упорядочивания операций с переменной в многопоточных программах, но не гарантирует атомарность.
Что гарантирует volatile?
- Видимость (Visibility): Любое изменение
volatile-переменной одним потоком немедленно становится видно всем другим потокам. Безvolatileизменения могут остаться в кэше процессора и не быть замеченными. - Запрет переупорядочивания (Happens-before): Операции чтения/записи
volatile-переменной создают барьер памяти. Операции до записи не могут быть переупорядочены после нее, а операции после чтения — не могут быть переупорядочены до него.
Чего НЕ гарантирует volatile?
- Атомарность составных операций: Операции вида
count++(чтение-изменение-запись) не являются атомарными, даже еслиcountобъявлен какvolatile. Для этого нужныsynchronizedили атомарные классы (AtomicInteger).
Пример правильного использования:
public class TaskRunner {
// Флаг для безопасной остановки потока извне
private volatile boolean running = true;
public void stop() {
running = false; // Изменение видно рабочему потоку сразу
}
public void run() {
while (running) { // Чтение всегда актуального значения
// Выполнение задачи...
}
}
}
Пример НЕправильного использования (отсутствие атомарности):
public class Counter {
private volatile int count = 0;
public void increment() {
count++; // НЕПРАВИЛЬНО! Операция не атомарна.
// Поток A: читает count (0)
// Поток B: читает count (0)
// Оба увеличивают значение до 1 и записывают.
// Итог: после двух вызовов count = 1, а не 2.
}
}
// Правильное решение: использовать java.util.concurrent.atomic.AtomicInteger
Вывод: Используйте volatile для простых флагов или переменных состояния, где операция записи атомарна сама по себе (простое присваивание). Для счетчиков или сложных состояний применяйте Atomic-классы или synchronized.