Ответ
Атомарные переменные (AtomicInteger, AtomicLong и др.) решают две ключевые задачи, актуальные даже при обработке одного запроса за раз:
- Гарантия видимости изменений (happens-before): Изменение атомарной переменной в одном потоке гарантированно становится видимым для всех последующих потоков. Хотя запрос
R1выполняется в потокеThread-A, запросR2может быть обработан вThread-B. Без атомарности/volatileобновление, сделанное вR1, может не отобразиться вR2из-за кэширования в памяти потока. - Атомарность составных операций: Операции вроде
incrementAndGet()выполняются как единое неделимое действие (чтение-модификация-запись). Это критично для корректного подсчета, даже если параллелизма нет.
Пример счетчика запросов:
private final AtomicInteger requestCounter = new AtomicInteger(0);
@GetMapping("/api/visit")
public int visit() {
// Гарантированно вернет уникальное и корректное значение для каждого запроса
return requestCounter.incrementAndGet();
}
Использование обычного int в этом сценарии может привести к тому, что некоторые инкременты "потеряются" для других потоков.