При ленивой или активной инициализации
Оператор if
является реализацией метода lazy initialization .
Более точная версия выглядит следующим образом:
private boolean firstTime = true;
private Stuff stuff;
public Stuff gimmeStuff() {
if (firstTime) {
firstTime = false;
stuff = new Stuff();
}
return stuff;
}
Что происходит, так это то, что в самый первый раз gimmeStuff()
вызывается, firstTime
будет true
, поэтому stuff
будет инициализирован new Stuff()
. При последующих вызовах firstTime
будет false
, поэтому new Stuff()
больше не будет вызываться.
Таким образом, stuff
инициализируется «лениво». На самом деле он не инициализируется до самого первого раза.
Смотри также
по безопасности потока
Надо сказать, что фрагмент не является потокобезопасным. Если имеется несколько потоков, то в некоторых условиях гонки new SingletonObjectDemo()
может вызываться несколько раз.
Одним из решений является метод synchronized getSingletonObject()
. Это, однако, приводит к накладным расходам синхронизации при ALL вызовах на getSingletonObject()
. Затем для исправления этой проблемы используется так называемая идиома с двойной проверкой блокировки , но в Java эта идиома фактически не работает до J2SE 5.0 с введением ключевого слова volatile
в новой модели памяти .
Само собой разумеется, что правильное применение шаблона синглтона не является тривиальной вещью.
Смотри также
Похожие вопросы
Effective Java 2nd Edition
Вот что говорит книга по этим предметам:
Item 71: Используйте ленивую инициализацию разумно
Как и в случае большинства оптимизаций, лучший совет для ленивой инициализации - «не делайте этого, если вам не нужно». Ленивая инициализация - обоюдоострый меч. Это снижает стоимость инициализации класса или создания экземпляра за счет увеличения стоимости доступа к лениво инициализированному полю. В зависимости от того, какая часть лениво инициализированных полей в конечном итоге требует инициализации, насколько дорогостоящей является их инициализация и как часто осуществляется доступ к каждому полю, ленивая инициализация (как и многие «оптимизации» на самом деле вредит производительности).
При наличии нескольких потоков ленивая инициализация сложна. Если два или более потоков совместно используют поле с отложенной инициализацией, очень важно использовать некоторую форму синхронизации, иначе могут возникнуть серьезные ошибки.
В большинстве случаев нормальная инициализация предпочтительнее ленивой инициализации.
Элемент 3: Применить свойство singleton с помощью частного конструктора или типа enum
Начиная с версии 1.5. Существует третий подход к реализации синглетонов. Просто создайте тип enum с одним элементом. [...] Этот подход функционально эквивалентен полевому подходу public
, за исключением того, что он более лаконичен, предоставляет механизм сериализации бесплатно и обеспечивает железную гарантию от множественных экземпляров, даже в условиях сложной сериализации или основанной на отражении атаки.
[...] Лучше всего реализовать одноэлементный тип перечисления.
Похожие вопросы
On enum
Singleton / Java-реализация:
О достоинствах и альтернативах одноэлементного шаблона: