Является ли Spring-бин с областью видимости Singleton потокобезопасным по умолчанию?

«Является ли Spring-бин с областью видимости Singleton потокобезопасным по умолчанию?» — вопрос из категории Spring, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Нет, по умолчанию singleton-бин в Spring не является потокобезопасным.

Почему? Spring управляет жизненным циклом singleton-бина, создавая один экземпляр на IoC-контейнер, который затем используется всеми запросами и потоками. Если состояние этого бина изменяемое (mutable), возникает состояние гонки (race condition).

Пример проблемного кода:

@Component // По умолчанию scope = "singleton"
public class UnsafeCounterService {
    private int count = 0; // Изменяемое состояние

    public void increment() {
        count++; // Неатомарная операция, небезопасна для потоков
    }

    public int getCount() {
        return count;
    }
}

Как обеспечить потокобезопасность?

  1. Старайтесь создавать stateless-бины: Без изменяемых полей. Это лучшая практика.
  2. Используйте synchronized или атомарные классы из java.util.concurrent.atomic:
    private final AtomicInteger count = new AtomicInteger(0);
    public void increment() {
        count.incrementAndGet();
    }
  3. Храните состояние в ThreadLocal переменных, если оно должно быть уникальным для потока.
  4. Измените область видимости бина на prototype, request или session, если логика требует отдельных экземпляров. Однако это влияет на производительность и память.

Вывод: Потокобезопасность singleton-бина — это ответственность разработчика, а не контейнера Spring.