Initialization-on-demand holder idiom
In der Softwareentwicklung bezeichnet das Entwurfsmuster Initialization on Demand Holder eine Implementierungsmöglichkeit eines sogenannten Lazy-Initialisierten Singleton, also eine Implementierung, bei der das Objekt erst bei der ersten Verwendung initialisiert wird. In allen Java-Versionen erlaubt es eine sichere, hochgradig parallelisierbare Lazy-Initialisierung mit guter Performance.[1]
Funktionsweise
[Bearbeiten | Quelltext bearbeiten]Folgendes Beispiel zeigt eine Implementierung des Idioms:
public class Something {
private Something() {}
private static class LazyHolder {
private static final Something INSTANCE = new Something();
}
public static Something getInstance() {
return LazyHolder.INSTANCE;
}
}
Sie basiert auf der Initialisierungsphase der Ausführung innerhalb der Java Virtual Machine (JVM), wie sie in der Java Language Specification (JLS) beschrieben ist.[2] Wenn die Klasse Something
durch die JVM geladen wird, geht sie durch den Initialisierungsprozess. Da die Klasse keine statischen Variablen zu initialisieren hat, wird der Initialisierungsprozess sofort abgeschlossen. Die statische Klassendefinition LazyHolder
innerhalb der Klasse wird nicht initialisiert, solange die JVM nicht erkennt, dass die Klasse LazyHolder
benötigt wird und ausgeführt werden muss. Die statische Klasse LazyHolder
wird nur ausgeführt, wenn die statische Methode getInstance
in der Klasse Something
verwendet wird. Beim ersten Aufruf der Methode lädt und initialisiert die JVM die Klasse LazyHolder
. Die Initialisierung der Klasse LazyHolder
resultiert ebenso in der Initialisierung der statischen Variable INSTANCE
welche den (privaten) Konstruktor der umschließenden Klasse Something
aufruft. Da die Initialisierungsphase einer Klasse laut der JLS garantiert seriell, also nicht-parallel, abläuft, ist keine weitere Synchronisierung in der statischen Methode getInstance
während des Ladens und der Initialisierung nötig. Da die Initialisierungsphase die statische Variable INSTANCE
in einer seriellen Operation beschreibt geben alle parallelen Aufrufe der getInstance
Methode dieselbe, korrekt initialisierte Variable INSTANCE
zurück.
Dies ergibt einen hoch-effizienten, Thread-sicheren „singleton“-Cache, ohne Synchronisierungs-Mehraufwand; Benchmarks ergaben, dass diese Implementierung deutlich schneller ist als viele andere mit Synchronisierungen.[3] Nichtsdestotrotz ist dieses Idiom Singleton-spezifisch und nicht erweiterbar auf Mehr-Objekt-Klassen.
Nur eine Gelegenheit zur Initialisierung
[Bearbeiten | Quelltext bearbeiten]Trotz der Eleganz dieses Ansatzes (welcher erstmals von Pugh beschrieben wurde) resultiert jeder Fehler während der Initialisierung der Klasse in einem nicht-nutzbaren Zustand der Holder-Klasse, was bedeutet, dass dieser Ansatz nur dann verwendet werden sollte, wenn sich der Entwickler sicher ist, dass die Initialisierung nicht fehlschlagen kann. Beispiel:
public class PughFail {
public static class Something {
private Something() {
super();
System.out.println(this.getClass().getName() + " called");
if (System.currentTimeMillis() > 0) {
System.out.println("EMULATING INIT FAILURE");
throw new RuntimeException("EMULATING INIT FAILURE");
}
}
private static class LazyHolder {
private static final Something INSTANCE = new Something();
}
public static Something getInstance() {
return LazyHolder.INSTANCE;
}
}
public static void main(String[] args) {
System.out.println("First try");
try {
Something.getInstance();
} catch (Throwable t) {
System.out.println(t);
}
System.out.println("Second try");
try {
Something.getInstance();
} catch (Throwable t) {
System.out.println(t);
}
}
}
Ausgabe:
First try PughFail$Something called EMULATING INIT FAILURE java.lang.ExceptionInInitializerError Second try java.lang.NoClassDefFoundError: Could not initialize class PughFail$Something$LazyHolder
Siehe auch
[Bearbeiten | Quelltext bearbeiten]Weblinks
[Bearbeiten | Quelltext bearbeiten]- The Java Memory Model auf cs.umd.edu
- JSR 133 (Java Memory Model) FAQ auf cs.umd.edu
- The “Double-Checked Locking is Broken” Declaration auf cs.umd.edu
Einzelnachweise
[Bearbeiten | Quelltext bearbeiten]- ↑ Das Double Checked Locking Idiom funktioniert nicht korrekt in Versionen vor Java 1.5.
- ↑ 12.4 of Java Language Specification.
- ↑ Fastest Thread-safe Singleton in the JVM. In: literatejava.com.