Ответ
Неблокирующее поведение AtomicInteger основано на принципе Compare-And-Swap (CAS).
Как работает CAS:
Это атомарная операция, выполняемая на уровне процессора. Она принимает три аргумента: адрес памяти (V), ожидаемое старое значение (A) и новое значение (B). Операция выполняется только если текущее значение по адресу V равно A. В этом случае оно заменяется на B. В противном случае (значение было изменено другим потоком) операция завершается неудачей.
Реализация в Java:
Классы атомиков (AtomicInteger, AtomicLong и др.) используют метод compareAndSet (и другие, построенные на нём), который внутри вызывает нативные методы (часто через sun.misc.Unsafe), задействующие аппаратную поддержку CAS.
Пример и внутренний цикл:
AtomicInteger counter = new AtomicInteger(0);
// Метод incrementAndGet() реализован примерно так:
public final int incrementAndGet() {
int current, next;
do {
current = get(); // 1. Читаем текущее значение
next = current + 1; // 2. Вычисляем новое
} while (!compareAndSet(current, next)); // 3. Пытаемся установить новое значение
return next;
}
Преимущества CAS перед блокировками (synchronized, Lock):
- Отсутствие блокировок: Потоки не приостанавливаются, что исключает дорогостоящие переключения контекста.
- Высокая производительность при низкой и средней конкуренции.
Недостатки (проблемы CAS):
- ABA-проблема: Поток может не заметить, что значение менялось с
AнаBи обратно наA. Решается использованиемAtomicStampedReference. - Busy-waiting (активное ожидание): При высокой конкуренции потоки могут многократно повторять цикл CAS, бесполезно расходуя процессорное время.