Ja, das ist notwendig. Es gibt verschiedene Methoden, mit denen Sie die Thread-Sicherheit mit verzögerter Initialisierung erreichen können:
Drakonische Synchronisation:
private static YourObject instance;
public static synchronized YourObject getInstance() {
if (instance == null) {
instance = new YourObject();
}
return instance;
}
Diese Lösung erfordert, dass jeder Thread synchronisiert wird, obwohl dies in Wirklichkeit nur die ersten sein müssen.
Überprüfen Sie die Synchronisation :
private static final Object lock = new Object();
private static volatile YourObject instance;
public static YourObject getInstance() {
YourObject r = instance;
if (r == null) {
synchronized (lock) { // While we were waiting for the lock, another
r = instance; // thread may have instantiated the object.
if (r == null) {
r = new YourObject();
instance = r;
}
}
}
return r;
}
Diese Lösung stellt sicher, dass nur die ersten Threads, die versuchen, Ihren Singleton zu erwerben, den Prozess des Erwerbs der Sperre durchlaufen müssen.
Initialisierung auf Abruf :
private static class InstanceHolder {
private static final YourObject instance = new YourObject();
}
public static YourObject getInstance() {
return InstanceHolder.instance;
}
Diese Lösung nutzt die Garantien des Java-Speichermodells für die Klasseninitialisierung, um die Thread-Sicherheit zu gewährleisten. Jede Klasse kann nur einmal geladen werden und wird nur geladen, wenn sie benötigt wird. Das heißt, das erste Mal getInstance
wird aufgerufen, InstanceHolder
geladen und instance
erstellt, und da dies von ClassLoader
s gesteuert wird , ist keine zusätzliche Synchronisation erforderlich.
Draconian synchronization
undDouble check synchronization
getInstance () - Methode muss statisch sein!static
, aber es könnte mehr Sinn machen , wenn sie waren. Wie gewünscht geändert.r
wird für die Richtigkeit nicht benötigt. Es ist nur eine Optimierung, um den Zugriff auf das flüchtige Feld zu vermeiden, da dies weitaus teurer ist als der Zugriff auf eine lokale Variable.Dieses Muster führt eine thread-sichere Lazy-Initialisierung der Instanz ohne explizite Synchronisation durch!
Es funktioniert, weil es den Klassenlader verwendet, um die gesamte Synchronisation für Sie kostenlos durchzuführen: Auf die Klasse
MySingleton.Loader
wird zuerst innerhalb dergetInstance()
Methode zugegriffen , sodass dieLoader
Klasse geladen wird, wenngetInstance()
sie zum ersten Mal aufgerufen wird. Darüber hinaus garantiert der Klassenladeprogramm, dass alle statischen Initialisierungen abgeschlossen sind, bevor Sie Zugriff auf die Klasse erhalten - das gibt Ihnen Thread-Sicherheit.Es ist wie Magie.
Es ist dem Aufzählungsmuster von Jhurtado eigentlich sehr ähnlich, aber ich finde das Aufzählungsmuster ein Missbrauch des Aufzählungskonzepts (obwohl es funktioniert)
quelle
final
sollte hinzugefügt werden. Getan.Wenn Sie in einer Multithread-Umgebung in Java arbeiten und sicherstellen müssen, dass alle diese Threads auf eine einzelne Instanz einer Klasse zugreifen, können Sie eine Aufzählung verwenden. Dies hat den zusätzlichen Vorteil, dass Sie die Serialisierung leichter handhaben können.
und dann lassen Sie einfach Ihre Threads Ihre Instanz wie folgt verwenden:
quelle
Ja, Sie müssen
getInstance()
synchronisieren. Wenn dies nicht der Fall ist, kann es vorkommen, dass mehrere Instanzen der Klasse erstellt werden können.Stellen Sie sich den Fall vor, in dem zwei Threads gleichzeitig aufgerufen
getInstance()
werden. Stellen Sie sich nun vor, T1 wird kurz nach derinstance == null
Prüfung ausgeführt, und dann wird T2 ausgeführt. Zu diesem Zeitpunkt wird die Instanz nicht erstellt oder festgelegt, sodass T2 die Prüfung besteht und die Instanz erstellt. Stellen Sie sich nun vor, die Ausführung wechselt zurück zu T1. Jetzt wird der Singleton erstellt, aber T1 hat die Prüfung bereits durchgeführt! Es wird fortfahren, das Objekt erneut zu erstellen! DasgetInstance()
Synchronisieren verhindert dieses Problem.Es gibt einige Möglichkeiten, Singletons threadsicher zu machen, aber die
getInstance()
Synchronisierung ist wahrscheinlich die einfachste.quelle
Enum Singleton
Der einfachste Weg, einen Singleton zu implementieren, der threadsicher ist, ist die Verwendung einer Aufzählung
Dieser Code funktioniert seit der Einführung von Enum in Java 1.5
Doppelte Verriegelung
Wenn Sie einen „klassischen“ Singleton codieren möchten, der in einer Multithread-Umgebung (ab Java 1.5) funktioniert, sollten Sie diesen verwenden.
Dies ist vor 1.5 nicht threadsicher, da die Implementierung des flüchtigen Schlüsselworts anders war.
Frühes Laden von Singleton (funktioniert bereits vor Java 1.5)
Diese Implementierung instanziiert den Singleton beim Laden der Klasse und bietet Thread-Sicherheit.
quelle
Sie können auch einen statischen Codeblock verwenden, um die Instanz beim Laden der Klasse zu instanziieren und Probleme mit der Thread-Synchronisierung zu vermeiden.
quelle
instance
endgültig machen 2. Sie solltengetInstance()
statisch machen .In diesem Beitrag erfahren Sie, wie Sie Singleton am besten implementieren können.
Was ist ein effizienter Weg, um ein Singleton-Muster in Java zu implementieren?
Dies hängt davon ab, wie Sie die Methode implementiert haben. Wenn Sie die doppelte Sperre ohne flüchtige Variable verwenden, erhalten Sie möglicherweise ein teilweise erstelltes Singleton-Objekt.
Weitere Informationen finden Sie in dieser Frage:
Warum wird in diesem Beispiel der doppelt überprüften Verriegelung flüchtig verwendet?
Nicht erforderlich, wenn Sie den Singleton wie folgt implementieren
Weitere Informationen finden Sie in dieser Frage
Java Singleton Design Pattern: Fragen
quelle
Quelle: Effektives Java -> Punkt 2
Es wird empfohlen, es zu verwenden, wenn Sie sicher sind, dass die Klasse immer Singleton bleibt.
quelle