In diesem Beitrag untersuchen wir verschiedene Möglichkeiten zur Implementierung eines Thread-sicheren Singletons in Java, einschließlich eifriger Initialisierung und doppelt überprüfter Sperrung und der innere statische Klasse-Ansatz. Wir werden auch diskutieren, warum das letzte Schlüsselwort für die Gewährleistung der Integrität eines Singletons von Vorteil ist.
Singletons sind nützlich, wenn Sie in der gesamten Anwendung genau eine Instanz einer Klasse benötigen. Zu den häufigsten Anwendungsfällen gehört die Verwaltung gemeinsam genutzter Ressourcen wie Protokollierung, Konfiguration oder Verbindungspools. Ein Singleton stellt sicher, dass mehrere Anfragen zum Zugriff auf eine Klasse dieselbe Instanz nutzen, anstatt neue zu erstellen.
Das Eager-Initialisierungsmuster erstellt die Singleton-Instanz, wenn die Klasse geladen wird. Dies ist unkompliziert und gewährleistet Thread-Sicherheit, da die Instanz erstellt wird, wenn die Klasse von der JVM geladen wird.
public final class Singleton { // Instance is created at class loading time private static final Singleton INSTANCE = new Singleton(); // Private constructor prevents instantiation from other classes private Singleton() {} public static Singleton getInstance() { return INSTANCE; } }
Vorteile:
Nachteile:
Wann man es verwendet: Eine eifrige Initialisierung ist am besten, wenn die Singleton-Klasse leichtgewichtig ist und Sie sicher sind, dass sie während der Laufzeit der Anwendung verwendet wird.
In Fällen, in denen Sie die Erstellung des Singletons verzögern möchten, bis er benötigt wird (bekannt als verzögerte Initialisierung), bietet doppelt überprüftes Sperren eine Thread-sichere Lösung. Es verwendet eine minimale Synchronisierung und stellt sicher, dass die Instanz nur erstellt wird, wenn zum ersten Mal darauf zugegriffen wird.
public final class Singleton { // Marked as final to prevent subclassing // volatile ensures visibility and prevents instruction reordering private static volatile Singleton instance; // Private constructor prevents instantiation from other classes private Singleton() {} public static Singleton getInstance() { if (instance == null) { // First check (no locking) synchronized (Singleton.class) { // Locking if (instance == null) { // Second check (with locking) instance = new Singleton(); } } } return instance; } }
Erste Prüfung: Die if (instance == null)-Prüfung außerhalb des synchronisierten Blocks ermöglicht es uns, eine Sperrung bei jedem Aufruf von getInstance() zu vermeiden. Dies verbessert die Leistung, indem der synchronisierte Block für zukünftige Aufrufe nach der Initialisierung umgangen wird.
Synchronisierter Block: Sobald die Instanz null ist, stellt die Eingabe des synchronisierten Blocks sicher, dass nur ein Thread die Singleton-Instanz erstellt. Andere Threads, die diesen Punkt erreichen, müssen warten, um Race Conditions zu vermeiden.
Zweite Prüfung: Innerhalb des synchronisierten Blocks überprüfen wir die Instanz erneut, um sicherzustellen, dass kein anderer Thread sie initialisiert hat, während der aktuelle Thread wartete. Durch diese Doppelprüfung wird sichergestellt, dass nur eine Singleton-Instanz erstellt wird.
Das Schlüsselwort volatile ist im doppelt überprüften Sperrmuster unerlässlich, um eine Neuordnung der Anweisungen zu verhindern. Ohne sie wäre die Anweisung „instance = new Singleton();“ kann für andere Threads als abgeschlossen erscheinen, bevor es vollständig initialisiert ist, was dazu führt, dass eine teilweise erstellte Instanz zurückgegeben wird. volatile garantiert, dass eine Instanz, sobald sie nicht null ist, vollständig aufgebaut und für alle Threads sichtbar ist.
Das letzte Schlüsselwort wird hier verwendet, um Unterklassen zu verhindern. Das Markieren der Singleton-Klasse als endgültig hat zwei Hauptvorteile:
Verhindert Unterklassenbildung: Indem wir die Klasse endgültig machen, verhindern wir, dass andere Klassen sie erweitern. Dadurch wird sichergestellt, dass nur eine Instanz der Singleton-Klasse existieren kann, da die Unterklassenbildung zu zusätzlichen Instanzen führen könnte, die das Singleton-Muster zerstören würden.
Signalisiert Unveränderlichkeit: final dient als klarer Indikator für andere Entwickler, dass die Singleton-Klasse unveränderlich sein soll und nicht erweitert werden sollte. Dadurch ist der Code leichter zu verstehen und zu warten.
Kurz gesagt, final stärkt die Integrität des Singletons und hilft, unerwartetes Verhalten durch Unterklassen zu vermeiden.
Vorteile:
Nachteile:
Wann man es verwendet: Dieses Muster ist nützlich, wenn die Singleton-Klasse ressourcenintensiv ist und möglicherweise nicht immer benötigt wird, oder wenn die Leistung in einer Multithread-Umgebung ein Problem darstellt.
Ein alternativer Thread-sicherer Ansatz zur verzögerten Initialisierung ist das Muster innere statische Klasse. Dies nutzt den Klassenlademechanismus von Java, um die Singleton-Instanz nur dann zu initialisieren, wenn sie benötigt wird, ohne explizite Synchronisierung.
public final class Singleton { // Instance is created at class loading time private static final Singleton INSTANCE = new Singleton(); // Private constructor prevents instantiation from other classes private Singleton() {} public static Singleton getInstance() { return INSTANCE; } }
In diesem Muster wird die SingletonHelper-Klasse nur geladen, wenn getInstance() zum ersten Mal aufgerufen wird. Dies löst die Initialisierung von INSTANCE aus und sorgt so für verzögertes Laden, ohne dass synchronisierte Blöcke erforderlich sind.
Vorteile:
Nachteile:
Wann man es verwendet: Verwenden Sie das innere statische Klassenmuster, wenn Sie eine verzögerte Initialisierung mit sauberem, wartbarem Code wünschen. Dies ist aufgrund der Einfachheit und Thread-Sicherheit oft die bevorzugte Wahl.
Wir haben uns drei beliebte Möglichkeiten angesehen, einen Thread-sicheren Singleton in Java zu implementieren:
Jeder Ansatz hat seine Stärken und eignet sich für unterschiedliche Szenarien. Probieren Sie sie in Ihren eigenen Projekten aus und finden Sie heraus, welches für Sie am besten funktioniert! Lassen Sie mich in den Kommentaren wissen, wenn Sie einen bevorzugten Ansatz oder Fragen haben.
Viel Spaß beim Codieren! ????
Das obige ist der detaillierte Inhalt vonLass deinen Singleton nicht kaputt gehen! Hier erfahren Sie, wie Sie es in Java zu % Thread-sicher machen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!