Что такое паттерн Double-Checked Locking?

«Что такое паттерн Double-Checked Locking?» — вопрос из категории Тестирование, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Double-Checked Locking (DCL) — это паттерн для ленивой инициализации синглтона, обеспечивающий потокобезопасность с минимальными накладными расходами на синхронизацию после создания объекта.

Ключевая идея: Проверить условие инициализации дважды:

  1. Первая проверка — без блокировки (для скорости, если объект уже создан).
  2. Вторая проверка — внутри синхронизированного блока (для гарантии корректности в многопоточной среде).

Пример реализации на Java:

public class Singleton {
    // Ключевое слово volatile критически важно для корректной работы
    private static volatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) { // Первая проверка (без блокировки)
            synchronized (Singleton.class) {
                if (instance == null) { // Вторая проверка (с блокировкой)
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

Зачем нужен каждый элемент?

  • Первая проверка (instance == null): Избегает дорогостоящей блокировки (synchronized) при каждом вызове после инициализации объекта.
  • Блок synchronized: Гарантирует, что только один поток сможет создать экземпляр.
  • Ключевое слово volatile: Предотвращает проблему частично инициализированного объекта из-за переупорядочивания инструкций процессором (memory reordering). Без volatile другой поток может получить ссылку на объект, конструктор которого ещё не завершил выполнение.

Альтернативы (в Java):

  • Статическая инициализация при загрузке класса (public static final Singleton INSTANCE = new Singleton();).
  • Использование enum (рекомендованный Джошуа Блохом способ).
  • LazyHolder (Initialization-on-demand holder idiom).