Ответ
Double-Checked Locking (DCL) — это паттерн для ленивой инициализации синглтона, обеспечивающий потокобезопасность с минимальными накладными расходами на синхронизацию после создания объекта.
Ключевая идея: Проверить условие инициализации дважды:
- Первая проверка — без блокировки (для скорости, если объект уже создан).
- Вторая проверка — внутри синхронизированного блока (для гарантии корректности в многопоточной среде).
Пример реализации на 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).