Heim  >  Artikel  >  Java  >  Ausführliche Erläuterung, wie die Muster Hungry Man und Lazy Man im Java-Singleton-Modus implementiert werden

Ausführliche Erläuterung, wie die Muster Hungry Man und Lazy Man im Java-Singleton-Modus implementiert werden

PHPz
PHPznach vorne
2023-04-27 12:40:071403Durchsuche

Was ist das Singleton-Muster?

Es stellt sicher, dass nur eine Instanz einer bestimmten Klasse im Programm vorhanden ist, anstatt mehrere Instanzen zu erstellen, was die Effizienz verbessert.

Im Single-Interest-Modus wird im Allgemeinen nur eine getInstance()-Methode bereitgestellt, um das Instanzobjekt abzurufen, und die setInstance()-Methode wird nicht bereitgestellt. Der Zweck besteht darin, die Instanziierung anderer Instanzobjekte zu vermeiden.

Es gibt zwei Modi im Singleton-Modus, einer ist der Hungrig-Modus und der andere ist der Lazy-Modus.

1. Das Konzept des Hungry-Han-Modus

Hungry-Han-Modus bedeutet, dass die Klasse sofort instanziiert wird, wenn sie geladen wird, und bei nachfolgenden Verwendungen nur eine Instanz angezeigt wird. 2. Hungry-Modus-Code . Es ist in Multithread-Situationen threadsicher.

2. Lazy-Modus

1. Das Konzept des Lazy-Modus
wird nicht direkt beim Laden der Klasse instanziiert, sondern beim Aufruf der angegebenen Instanzmethode, um sicherzustellen, dass sie beim Laden nicht verwendet wird Ich möchte es nicht verwenden. Im Allgemeinen ist er effizienter als der Hungry-Man-Modus.

2. Lazy-Modus in Single-Thread-Situationen

package thread.example;
//饿汉模式
public class HungrySingle {
//在类加载的时候就实例化了,类加载只有一次,所以值实例化出了一份该实例对象
    private static HungrySingle instance = new HungrySingle();
    public static HungrySingle getInstance() {
        return instance;
    }
}

3. Lazy-Modus in Multi-Thread-Situationen

(1) Gründe, warum der Lazy-Modus in Multi-Thread-Situationen unsicher ist Es ist möglich, dass beide Threads eine Instanz = Null erhalten. Dies liegt daran, dass Thread 2 zu diesem Zeitpunkt auch ein Instanzobjekt instanziiert, wenn er die Instanz in seinem eigenen County ändert, bevor er Zeit hat, die Instanz im Hauptspeicher zu ändern , es ist kein Singleton-Modus mehr. Die Hauptursache für dieses Problem besteht darin, dass die Instanz geändert und die Atomizität verloren geht. Um die Atomizität sicherzustellen, haben wir über eine Sperre nachgedacht, um Thread-Sicherheit zu erreichen.

(2) Lösungscodebeispiel

Version 1
package thread.example;
//单线程的懒汉模式
public class LazySingle {
    private static LazySingle instance = null;
    //只有在调用该方法的时候才实例化
    public static LazySingle getInstance() {
        if(instance == null) {
            instance = new LazySingle();
        }
        return instance;
    }
}
Obwohl der Code von Version 1 die Thread-Sicherheit gewährleistet, treten bei jedem Aufruf der Methode immer noch Probleme beim Sperren und Entsperren auf. Zur weiteren Optimierung können wir die Sperre reduzieren Die Granularität wird zur Verbesserung der Effizienz verwendet, da nach dem Hinzufügen von Sperren keine hohe Parallelität mehr möglich ist. Wir möchten die Effizienz jedoch dennoch verbessern und optimieren sie daher.

Version 2

Double if Judgement Locking verbessert die Effizienz

package thread.example;
//多线程安全下的懒汉模式
    public class LazySingle {
        private LazySingle() {
    }
    private static LazySingle instance = null;
    //只有在调用该方法的时候才实例化
    public static synchronized LazySingle getInstance() {
        if (instance == null) {
            instance = new LazySingle();
        }
        return instance;
    }
}

Erläuterung von Version 2

Die erste Ebene von if dient dazu, festzustellen, ob die Instanz erstellt wurde, und die zweite Ebene von synchronisiert dient dazu, sie in das aktuelle if einzugeben Threads konkurrieren um die Sperre, wenn sie in die dritte Ebene eintreten. Wenn sie nicht leer ist, instanziiert er das Objekt und gibt die Sperre dann frei. Die Instanz ist nicht mehr leer und nachfolgende Threads werden auf der dritten Ebene blockiert, wenn später beim Zugriff auf die Methode getInstance() festgestellt wird, dass die Instanz nicht mehr leer ist, sodass keine Notwendigkeit besteht, die Sperrressource zu belegen , denn auch der Wettbewerb um die Sperre nimmt viel Zeit in Anspruch. Durch diese Verarbeitung wird die Fadensicherheit gewährleistet und die Effizienz verbessert.

Der Zweck der Verwendung von volatile besteht darin, eine durch Compileroptimierung verursachte Neuordnung von Anweisungen zu verhindern. Das Ausführen eines neuen Objekts ist keine atomare Operation und kann in drei Schritte unterteilt werden:

1. Speicherplatz zuweisen 2. Instanziieren Sie das Objekt

3. Weisen Sie der Variablen einen Wert zu

    Wenn bei der obigen Ausführung 1 und 3 zuerst ausgeführt werden (vorausgesetzt, 2 wurde noch nicht abgeschlossen), liegt der Thread außerhalb der ersten Ebene von if wird zu diesem Zeitpunkt nicht als null beurteilt. Das Objekt wird zu diesem Zeitpunkt direkt zurückgegeben, dieses Objekt wird jedoch nur zur Hälfte ausgeführt, und die spätere Verwendung führt zu Thread-Sicherheitsproblemen.
  1. Volatile kann sicherstellen, dass diese drei Schritte ausgeführt werden müssen (unabhängig von der Reihenfolge, in der sie letztendlich ausgeführt werden), bevor externe Threads ausgeführt werden können. Zu diesem Zeitpunkt ist die Integrität des Objekts gewährleistet.

Das obige ist der detaillierte Inhalt vonAusführliche Erläuterung, wie die Muster Hungry Man und Lazy Man im Java-Singleton-Modus implementiert werden. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen