Idiom posiadacza inicjalizacji na żądanie
W inżynierii oprogramowania idiom posiadacza inicjalizacji na żądanie ( wzorzec projektowy ) to leniwie ładowany singleton . We wszystkich wersjach Javy ten idiom umożliwia bezpieczną, wysoce współbieżną, leniwą inicjalizację pól statycznych z dobrą wydajnością.
public class Coś { private Something () {} private static class LazyHolder { static final Something INSTANCE = new Something (); } public static Coś getInstance () { return LazyHolder . INSTANCJA ; } }
Implementacja idiomu opiera się na fazie inicjalizacji wykonania w wirtualnej maszynie Java (JVM), zgodnie ze specyfikacją języka Java (JLS). Kiedy klasa Something
jest ładowana przez JVM, klasa przechodzi inicjalizację. Ponieważ klasa nie ma żadnych zmiennych statycznych do zainicjowania, inicjalizacja kończy się trywialnie. w niej definicja klasy statycznej LazyHolder
nie jest inicjowana, dopóki JVM nie określi, że LazyHolder
musi zostać wykonany. Klasa statyczna LazyHolder
w klasie Something zostanie wywołana
metoda statyczna getInstance
, a za pierwszym razem JVM załaduje i zainicjuje klasę LazyHolder
. Inicjalizacja LazyHolder
powoduje inicjalizację zmiennej statycznej INSTANCE
poprzez wykonanie (prywatnego) konstruktora dla klasy zewnętrznej Something
. Ponieważ JLS gwarantuje, że faza inicjalizacji klasy będzie sekwencyjna, tj. niewspółbieżna, nie jest wymagana dalsza synchronizacja w statycznym getInstance
podczas ładowania i inicjalizacji. A ponieważ faza inicjalizacji zapisuje zmienną statyczną INSTANCE
w operacji sekwencyjnej, wszystkie kolejne współbieżne wywołania getInstance zwrócą
tę samą poprawnie zainicjowaną INSTANCE
bez ponoszenia dodatkowego narzutu synchronizacji.
Zastrzeżenia
Chociaż implementacja jest wydajną, bezpieczną dla wątków „pojedynczą” pamięcią podręczną bez narzutu synchronizacji i lepszą wydajnością niż synchronizacja bez walki, idiomu można używać tylko wtedy, gdy konstrukcja Something
gwarantuje, że nie zawiedzie. W większości implementacji JVM, jeśli konstrukcja Something
się nie powiedzie, kolejne próby zainicjowania go z tego samego modułu ładującego klasy zakończą się niepowodzeniem NoClassDefFoundError
.
Zobacz też
Linki zewnętrzne
- http://www.cs.umd.edu/~pugh/java/memoryModel/
- http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html
- http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html