← Назад к вопросам

Зачем делать переменную атомарной, если запросы в контроллер идут в одном потоке

1.7 Middle🔥 151 комментариев
#REST API и микросервисы#Многопоточность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Ответ: Атомарные переменные и многопоточность в контроллерах

Это распространённое заблуждение, что если запрос обрабатывается одним потоком, то переменные не нужно делать атомарными. На самом деле, в веб-приложениях один запрос != один поток приложения. Разберу подробно.

Основное недопонимание

Вот типичная ошибка в рассуждении:

// ❌ Неправильное понимание
public class UserCounter {
    private int count = 0; // Один запрос — один поток?
    
    @GetMapping("/increment")
    public int increment() {
        return ++count; // Вроде всё в одном потоке...
    }
}

НО это не так! Каждый новый запрос может обрабатываться другим потоком из пула потоков servlet'а.

Как на самом деле работают контроллеры

В Spring и других веб-фреймворках используется пул потоков:

// Симуляция того, как работает веб-сервер
public class TomcatThreadPool {
    private ExecutorService threadPool = Executors.newFixedThreadPool(10); // 10 потоков
    
    // Каждый запрос обрабатывается отдельным потоком
    public void handleRequest(HttpRequest request) {
        threadPool.execute(() -> {
            // Запрос 1 в потоке 1
            // Запрос 2 в потоке 2
            // Запрос 3 в потоке 3
            controller.handleRequest(request);
        });
    }
}

Проблема с обычными переменными

// ❌ Опасный код
public class UserCounter {
    private int count = 0; // Разделяется между всеми потоками!
    
    @GetMapping("/increment")
    public int increment() {
        // Три потока одновременно:
        // Поток 1: прочитал count=5, увеличивает
        // Поток 2: прочитал count=5, увеличивает
        // Поток 3: прочитал count=5, увеличивает
        // Результат: count=6, хотя должен быть 8!
        return ++count;
    }
}

// Это называется race condition (состояние гонки)

Решение с AtomicInteger

import java.util.concurrent.atomic.AtomicInteger;

// ✅ Правильный код
public class UserCounter {
    private AtomicInteger count = new AtomicInteger(0); // Потокобезопасно!
    
    @GetMapping("/increment")
    public int increment() {
        // Атомарная операция: прочитать и увеличить в одном шаге
        return count.incrementAndGet();
    }
}

Практический пример

Атомарные переменные необходимы для потокобезопасности в многопоточной среде, которой является любое веб-приложение. Пул потоков servlet контейнера обеспечивает параллельную обработку множества запросов одновременно.

Зачем делать переменную атомарной, если запросы в контроллер идут в одном потоке | PrepBro