Гарантирует ли аннотация @Singleton в Spring потокобезопасность бина?

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

Ответ

Нет. Аннотация @Singleton (или @Scope("singleton")) гарантирует, что контейнер Spring IoC создаст и будет возвращать один и тот же экземпляр бина для всех запросов. Однако она не обеспечивает потокобезопасность доступа к состоянию этого бина.

Потокобезопасность становится проблемой, если синглтон имеет изменяемое состояние (mutable state). Если несколько потоков одновременно изменяют данные бина, возникает состояние гонки (race condition).

Пример небезопасного синглтона:

@Component
@Scope("singleton") // Или просто @Component, т.к. singleton — scope по умолчанию
public class UnsafeCounter {
    private int count = 0; // Изменяемое состояние

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

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

  1. Stateless бины: Лучший подход — проектировать бины без изменяемого состояния.
  2. Синхронизация: Использовать ключевое слово synchronized или блоки java.util.concurrent.locks.
  3. Атомарные типы: Использовать классы из java.util.concurrent.atomic, например AtomicInteger.
  4. Неизменяемые объекты (Immutable): Хранить только final поля и возвращать новые экземпляры при изменении.

Пример исправленного счетчика:

@Component
public class SafeCounter {
    private final AtomicInteger count = new AtomicInteger(0);

    public void increment() {
        count.incrementAndGet(); // Атомарная и потокобезопасная операция
    }
}