tgoop.com/javaproglib/7003
Last Update:
В многопоточном коде даже простая операция count++ не является атомарной. Она распадается на три шага:
1. Прочитать значение переменной.
2. Увеличить его.
3. Записать обратно.
Если два потока выполнят это одновременно, получится гонка данных (race condition). Итоговое значение будет меньше ожидаемого.
🔹 Как решает проблему AtomicInteger
AtomicInteger — это класс из пакета java.util.concurrent.atomic, который предоставляет атомарные (неделимые) операции над целыми числами.
Под капотом он использует механизм CAS (Compare-And-Swap), который поддерживается на уровне процессора.
Принцип работы:
— Читаем текущее значение.
— Проверяем, не изменилось ли оно за это время.
— Если совпадает, записываем новое.
— Если нет, повторяем попытку (spin loop).
🔹 Пример использования
public class Counter {
private final AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet(); // атомарное ++
}
public int get() {
return count.get();
}
}
Здесь incrementAndGet() гарантирует, что два потока не «перетрут» друг друга, а каждый инкремент будет учтён.
🔹 Основные методы
▪️ get() — получить текущее значение.
▪️ set(int newValue) — установить новое значение.
▪️ incrementAndGet() / getAndIncrement() — инкремент.
▪️ decrementAndGet() — декремент.
▪️ addAndGet(int delta) — прибавить значение.
▪️ compareAndSet(int expect, int update) — вручную применить CAS.
🔹 Подводные камни
— Спин-блокировки
CAS может крутиться в цикле, пока не удастся обновить значение. При высокой конкуренции это нагружает процессор.
— ABA-проблема
Значение могло измениться на «A → B → A». Для простых счётчиков это не критично, но в сложных структурах данных используют AtomicStampedReference.
— Ограниченность
AtomicInteger работает только с int. Для более сложных случаев есть AtomicLong, AtomicReference, LongAdder (оптимизирован для высокой конкуренции).
🔹 Когда использовать
— Для простых счётчиков, метрик.
— В неблокирующих алгоритмах (lock-free).
— В высоконагруженных сценариях, где synchronized слишком дорог.
— Для сложных бизнес-операций над несколькими переменными (лучше использовать мьютексы или транзакции).
— При очень высокой конкуренции, может быть лучше взять LongAdder.
🔹 Итог
AtomicInteger — это лёгкий способ избавиться от гонок при работе с числами в многопоточности.
Это не магия, а всего лишь тонкая обёртка над CAS, встроенным в процессоры. Понимание этого механизма помогает писать по-настоящему безопасный и быстрый многопоточный код.
#CoreJava