Ответ
Атомарные переменные (java.util.concurrent.atomic) необходимы для выполнения простых атомарных операций (чтение-запись-модификация) над примитивами или ссылками в многопоточной среде без использования блокировок (synchronized). Они основаны на аппаратных инструкциях сравнения с обменом (CAS — Compare-And-Swap).
Типичный сценарий: потокобезопасный счётчик.
Проблема с volatile и synchronized:
// Только volatile НЕ решает проблему!
private volatile int counter = 0;
public void unsafeIncrement() {
counter++; // Операция НЕ атомарна (чтение, инкремент, запись)
}
// Решение с synchronized работает, но может быть избыточным
private int counter = 0;
public synchronized void safeButHeavyIncrement() {
counter++;
}
Решение с AtomicInteger:
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicCounter {
// Атомарная переменная
private final AtomicInteger counter = new AtomicInteger(0);
public void increment() {
// Атомарная операция инкремента
counter.incrementAndGet();
}
public int getValue() {
// Атомарное чтение
return counter.get();
}
// Пример более сложной атомарной операции
public void updateIfLower(int newValue) {
int oldValue;
do {
oldValue = counter.get();
// CAS-цикл: обновит значение только если оно всё ещё равно oldValue
} while (oldValue < newValue && !counter.compareAndSet(oldValue, newValue));
}
}
Ключевые классы и их применение:
AtomicInteger,AtomicLong— счётчики, идентификаторы.AtomicBoolean— флаги инициализации, флаги состояния.AtomicReference<V>— атомарное обновление ссылок на объекты (например, для кэша или конфигурации).AtomicIntegerArray,AtomicLongArray— работа с массивами.
Важное ограничение: Атомарные переменные гарантируют атомарность отдельной операции (например, incrementAndGet()). Для составных действий (проверить, а затем изменить), зависящих от нескольких переменных, всё ещё требуется синхронизация или использование AtomicReference с комплексными объектами.