Schreiben wir 5 Möglichkeiten zur Implementierung von Java Singleton und verschiedene Vor- und Nachteile

Dieser Artikel ist ein Nachdruck des Blogs.  https://munchkins-diary.hatenablog.com/entry/2018/11/21/040358

Vorwort

Hallo, ich bin ein Java / Scala-Entwickler, der möglicherweise bereit ist, bereinigt zu werden, wenn es sich nach dem Erlernen von G1GC um eine JVM handelt.

Das Designmuster namens Singleton-Muster ist sehr berühmt, daher kennt es jeder, aber Java hat verschiedene Möglichkeiten, Singleton mit anderen Sprachspezifikationen als der üblichen Schreibweise zu schreiben. Deshalb werde ich es dieses Mal vorstellen. Ich werde. Ich kannte Bill Pugh übrigens erst, als ich Japan verließ.

Apropos Singleton-Muster: Bei der Erläuterung der Vorzüge handelt es sich um ein Entwurfsmuster, das häufig abstrakt erklärt wird, z. B. die Möglichkeit, eine Instanz zu erstellen, die in Bezug auf die Objektorientierung eindeutig sein muss.

Persönlich verwende ich es oft, wenn ich schwere und starke Nebenwirkungen wie die Kommunikation mit der Außenwelt und den Zugriff auf Middleware sammle und es dann in einem FlyWeight-Tick in Kombination mit einer abstrakten Factory implementiere.

Im Gegenteil, ich verwende es auch gerne, wenn ich eine objektähnlichere Implementierung ohne Verwendung von Util-Klassen implementiere, für die eine vollständig funktionierende Implementierung erforderlich ist.

Es ist kein Singleton-Muster, aber ich habe den Eindruck, dass die Singleton-Richtlinie von Spring Bean der früheren Verwendung von Singleton ähnelt. (Es sieht so aus, als würde es hier fliegen, also verpassen Sie es nicht. Wenn Sie eine bessere Möglichkeit haben, es zu verwenden, hinterlassen Sie bitte einen Kommentar!)

Dann das Hauptthema!

Gewöhnlicher Singleton

Eine Methode zur Sicherstellung der Eindeutigkeit, indem neue externe Klassen verboten werden, indem dem Klassenwert eine Instanz zugewiesen und der Konstruktor privat gemacht wird.

class NormalSingleton{
  // Singleton instance.
  private static final NormalSingleton INSTANCE = new NormalSingleton();
  // private constructor to prevent instantiation from other classes.
  private NormalSingleton() {}
  // static method to get the instance.
  public static NormalSingleton getInstance() {
    return INSTANCE;
  }
}

Wie Sie alle wissen, ist dies die gebräuchlichste Schreibweise. Dies ist genug für eine leichte Klasse. Da INSTANCE ein statisches Mitglied ist, wird es beim Laden der Klasse in den Heap geladen.

Es scheint eine Möglichkeit zu geben, INSTANCE öffentlich zu machen, aber ich persönlich möchte nicht, dass Klassenmitglieder direkt referenziert werden, also rufe ich es von der öffentlichen statischen Methode auf.

verdienen

** ・ Einfach und leicht zu implementieren ** ** ・ Auch für Anfänger leicht verständlich ** ** ・ Gewindesicher **

Fehler

** - Nicht für schwere Klassen geeignet, da beim Laden der Klasse immer eine Instanz erstellt wird ** ** - Nicht unbedingt ein Singleton, da der Konstruktor durch Reflexion zugänglich ist **

Verwenden

Es ist eine universelle Implementierungsmethode, daher werde ich sie erwähnen, aber wenn ich es wage, sie zu erwähnen ** · Lernen ** ** · Klassen, von denen bekannt ist, dass sie auf der Serverseite häufig verwendet werden ** ** ・ Eine Klasse, die nicht schwer ist, aber im objektorientierten Sinne Singleton sein möchte ** Ist es da?

Generierung verzögern

Eine Methode, bei der eine Instanz erstellt wird, indem zuerst die Methode getInstance aufgerufen wird, ohne einen Anfangswert zu haben, und die erstellte Instanz ab dem zweiten Mal wiederverwendet wird.

class DelaySingleton {
  // field for singleton instance without any initial value (null)
  private static DelaySingleton instance;

  // private constructor to block the instantiation from other class.
  private DelaySingleton () {}

  // method to get the instance
  public static getInstance() {
    // create instance only in initial call of this method.
    if (instance == null) {
      instance = new DelaySingleton();
    }
    return instance;
  }
}

Dies ist auch ein bekanntes und verzögertes Generierungsmuster. Es wird oft in etwas schwereren Klassen verwendet. Es wird häufig verwendet, weil es einfach zu implementieren ist und der Mechanismus klar ist. Wie Sie jedoch sehen können, handelt es sich nicht um ThreadSafe. In einer Umgebung, in der parallele Verarbeitung ausgeführt wird, wird das Muster verwendet, das mithilfe von Synchronized in ThreadSafe erstellt wurde und das als Nächstes eingeführt wird.

verdienen

** ・ Einfach und leicht zu implementieren ** ** ・ Auch für Anfänger leicht verständlich ** ** - Kann die Erzeugung schwerer Klassen bis kurz vor ihrer Verwendung verzögern **

Fehler

** ・ Nicht gewindesicher ** ** ・ Da die Instanz zusätzlich zum Konstruktor nicht endgültig ist, kann sie über Reflection neu geschrieben werden und ist kein Singleton mehr **

Verwenden

** · Lernen ** ** ・ Stapelverarbeitung ohne Multithreading **

ThreadSafe mit synchronisiert

Eine Methode zum Einschließen des Teils, in dem die Instanz erstellt wird, mit einem Synchronisationsblock und zum festen Eingrenzen des neuen Aufrufs auf einmal.

class SynchronizedSingleton {
  // field for singleton instance without any initial value (null)
  private static SynchronizedSingleton instance;

  // private constructor to protect the instantiation from other class.
  private SynchronizedSingleton(){}

  // method to get the instance
  public static SynchronizedSingleton getInstance(){
    // check if the instance is already instantiated.
    if(instance == null){
      // block the multiple access from multiple thread
      synchronized (SynchronizedSingleton.class) {
        // check again, can be non-null, 
        // since the instance already generated just at the process just before 
        if(instance == null){
          instance = new SynchronizedSingleton();
        }
      }
    }
    return instance;
  }
}

Dies kann auch recht vertraut sein. Dies ist die Methode, die in Designmusterbüchern und vielen einführenden Artikeln eingeführt wurde. Übrigens mag ich diese Art zu schreiben ehrlich gesagt nicht.

verdienen

** ・ Gewindesicher ** ** - Die Generierung schwerer Instanzen kann bis kurz vor ihrer Verwendung verzögert werden **

Fehler

** ・ Sato synchronisiert kann zu Leistungseinbußen führen ** ** ・ Da INSTANCE zusätzlich zum Konstruktor nicht endgültig ist, kann es durch Reflektion neu geschrieben werden und ist nicht mehr Singleton ** ** ・ Schwer zu schreiben und zu lesen **

Verwenden

** · Lernen ** ** ・ Stapel, der Multithreading stark nutzt ** ** ・ Serverseitige Anwendung, die von Tomcat usw. betrieben wird ** Synchronized Singleton hat viele Probleme, daher verwende ich persönlich häufig Bill Push Singleton, der später beschrieben wird. Bill Pugh Singleton Singleton verwendet Javas Sprachspezifikation, dass der Klassenwert der inneren Klasse erst bei der ersten Referenz in den Speicher eingelesen wird.

class BillPushSingleton{
  // class to hold the instance as final
  private class SingletonHolder{
    // this instance won't be loaded to memory until initial reference
    // normally, class value will be loaded into memory when the class is loaded to JVM with class loader.
    private static final BillPushSingleton INSTANCE = new BillPushSingleton();
  }

  // private constructor to prevent instantiation from other classes
  private BillPushSingleton() {}

  // method to get the instance
  public static BillPushSingleton getInstance() {
    // this instance will be instantiated at the initial call only.
    return SingletonHolder.INSTANCE;   
  }
}

Es mag ein Schreibstil sein, der in Japan (soweit ich weiß) nicht sehr vertraut ist, aber es ist ein Schreibstil, den Entwickler in Übersee bevorzugen. Ich denke auch, dass es einfach und elegant ist, also verwende ich diese Schreibmethode im Grunde genommen, wenn ich einen Singleton mit verzögerter Generation mache.

** Erklärung **

Derzeit wird der Klassenwert einer normalen Klasse instanziiert, wenn der Klassenlader die Klasse in die JVM lädt und im permanenten Bereich des Heaps gespeichert wird. (Wenn Sie den permanenten Bereich nicht kennen, lesen Sie O'Reillys Java Performance!) Die in der inneren Klasse deklarierten Konstanten sind jedoch nicht neu, wenn auf die übergeordnete Klasse selbst verwiesen wird, sondern neu und werden nur dann im permanenten Bereich beibehalten, wenn die übergeordnete Klasse auf die innere Klasse verweist. Wird sein. Dadurch kann INSTANCE in dieser Klasse threadsicher sein und die Generierung verzögern, bis die Methode getInstance aufgerufen wird. (Tatsächlich handelt es sich hierbei um eine Class Loader-Spezifikation, und es handelt sich nicht um einen speziellen Hack.)

verdienen

** ・ Einfach und leicht zu implementieren ** ** ・ Gewindesicher ** ** - Kann die Generierung schwerer Instanzen bis kurz vor ihrer Verwendung verzögern ** ** ・ Keine Sorgen über Leistungseinbußen aufgrund von Synchronized **

Fehler

** - Es ist nicht ausschließlich Singleton, da es durch Reflexion instanziiert werden kann ** ** ・ Es ist faul, Leuten zu erklären, die keine Kenntnisse über JVM und Class Loader haben (der Hauptgrund, warum ich diesen Artikel geschrieben habe) **

Verwenden

** ・ Stapel, der Multithreading stark nutzt ** ** ・ Serverseitige Anwendung, die von Tomcat usw. betrieben wird **

Dies ist übrigens immer noch kein strenger Singleton. Solange der Konstruktor erhalten bleibt, kann es sich nicht um einen strengen Singleton handeln.

Enum Singleton Singleton verwendet Javas Sprachspezifikation, dass Enum die einzige Instanz weltweit ist

enum EnumSingleton {
  // enum with only one element.
  // this element will act as same with instance of other impl pattern.
  INSTANCE("Now it is clear for you to see this is singleton, ahh??");

  // Constructor to make this sample code looks like class.
  // this constructor is unable to be called even from reflection as Java lang spec.
  private EnumSingleton(String dummyMessage) {
    this.dummyMessage = dummyMessage;
  }

  // dummy filed to make this sample code look like the other impl pattern
  private String dummyMessage;
  // dummy method to show this enum can work like normal class.
  public String sampleMethod() {
    return "this method is sample to show this is not just the normal enum.";
  }
}

Diese Implementierungsmethode kann ziemlich berühmt sein. Als Java-Sprachspezifikation ist Enum ein strikter Singleton, und neue Instanzen können nicht einmal durch Reflektion erstellt werden. Nur als Aufzählung implementiertes Singleton ist ein echtes Singleton. Übrigens denke ich nicht, dass es normal ist, also habe ich es nie benutzt, nur weil ich es als Wissen kenne.

verdienen

** ・ Strenger Singleton ** ** ・ Gewindesicher **

Fehler

** ・ Ich verstehe die Bedeutung von enum nicht, weil die Implementierung nicht gut ist ** ** ・ Schnittstellen und abstrakte Klassen können nicht verwendet werden, was die Kombination mit anderen Entwurfsmustern erschwert ** ** ・ Verzögerungsgenerierung ist nicht möglich ** ** ・ Ich kann es nicht gut erklären, wenn ich gefragt werde, warum ich es getan habe **

Verwenden

** ・ Stapel, der Multithreading stark nutzt ** ** ・ Serverseitige Anwendung, die von Tomcat usw. betrieben wird ** ** ・ Beruhigt Entwickler, die anfangen zu weinen, weil sie die Kluft zwischen Ideal und Realität nicht ertragen können **

Zusammenfassung

Ich habe verschiedene Möglichkeiten eingeführt, um das mir bekannte Singleton-Muster zu implementieren. Persönlich denke ich, ich sollte nur Bill Pugh Singleton und gewöhnlichen Singleton verwenden. Übrigens verwende ich oft Enum Singleton, aber es ist ein traditioneller Schreibstil und nicht, weil ich ihn verwendet habe. Es ist eine persönliche Geschichte. Na dann!

Recommended Posts

Schreiben wir 5 Möglichkeiten zur Implementierung von Java Singleton und verschiedene Vor- und Nachteile
Ich möchte verschiedene Funktionen mit Kotlin und Java implementieren!
Vor- und Nachteile von Java
[Rails] Verschiedene Möglichkeiten zum Schreiben in Seed-Dateien
Ich möchte schnell von Java nach SQLite schreiben
[Java] Ich habe Polymorphismus studiert, daher werde ich zusammenfassen, wie man ihn verwendet und welche Vorzüge er hat.
Ich habe versucht, TCP / IP + BIO mit JAVA zu implementieren
Ich habe versucht, die Firebase-Push-Benachrichtigung in Java zu implementieren
[Java] Arten von Kommentaren und wie man sie schreibt
Schreiben Sie zur Implementierung den Test und codieren Sie den Prozess
Ich habe versucht, Sterling Sort mit Java Collector zu implementieren
[Java] Ich habe versucht, die Yahoo API-Produktsuche zu implementieren
Ich habe versucht, die Methode der gegenseitigen Teilung von Eugrid in Java zu implementieren
Ich habe versucht, die Grundlagen von Kotlin und Java zusammenzufassen
Ich möchte eine Liste mit Kotlin und Java erstellen!
Ich möchte eine Funktion mit Kotlin und Java erstellen!
Ich habe versucht, Java Optional und Guard-Klausel koexistieren zu lassen
Schreiben und Notizen bei der Migration von VB zu JAVA
Wie schreibe ich einen Java-Kommentar
[Java] So implementieren Sie Multithreading
[Java] Verschiedene Zusammenfassungen an die Leiter von Klassen und Mitgliedern
Ich möchte in der Lage sein, selbst reguläre Ausdrücke zu denken und zu schreiben. ..
Ich möchte nur Java mit Eclipse auf meinem Mac schreiben
Ich möchte mit Kotlin und Java zum vorherigen Bildschirm zurückkehren!
Grundlagen der Java-Entwicklung ~ Schreiben von Programmen (Variablen und Typen) ~
Ich habe versucht, die Methoden von Java String und StringBuilder zusammenzufassen