856 Stimmen

Wie kann man ein Singleton-Muster in Java effizient implementieren?

Wie lässt sich ein Singleton-Entwurfsmuster in Java effizient implementieren?

9voto

NullPoiиteя Punkte 54880

Ich würde sagen, ein enum singleton.

Singleton mit einer enum in Java ist im Allgemeinen eine Möglichkeit, eine enum singleton zu deklarieren. Ein enum singleton kann Instanzvariablen und Instanzmethoden enthalten. Der Einfachheit halber sollten Sie auch beachten, dass Sie bei der Verwendung einer Instanzmethode die Thread-Sicherheit dieser Methode sicherstellen müssen, wenn sie den Zustand des Objekts beeinflusst.

Die Verwendung eines Enums ist sehr einfach zu implementieren und hat keine Nachteile in Bezug auf serialisierbare Objekte, die auf andere Weise umgangen werden müssen.

/**
* Singleton pattern example using a Java Enum
*/
public enum Singleton {
    INSTANCE;
    public void execute (String arg) {
        // Perform operation here
    }
}

Sie können darauf zugreifen über Singleton.INSTANCE und es ist viel einfacher als der Aufruf der getInstance() Methode auf Singleton.

1.12 Serialisierung von Enum-Konstanten

Enum-Konstanten werden anders serialisiert als gewöhnliche serialisierbare oder externalisierbare Objekte. Die serialisierte Form einer Enum-Konstante besteht nur aus ihrem Namen; Feldwerte der Konstante sind in der Form nicht vorhanden. Um eine Enum-Konstante zu serialisieren, ObjectOutputStream schreibt den von der Methode name der Enum-Konstante zurückgegebenen Wert. Um eine Enum-Konstante zu deserialisieren, ObjectInputStream liest den Namen der Konstante aus dem Stream; die deserialisierte Konstante wird dann durch den Aufruf der java.lang.Enum.valueOf Methode, wobei der Enum-Typ der Konstante zusammen mit dem empfangenen Konstantennamen als Argumente übergeben werden. Wie andere serialisierbare oder externalisierbare Objekte können Enum-Konstanten als Ziel von Rückverweisen dienen, die später im Serialisierungsstrom erscheinen.

Der Prozess, mit dem Enum-Konstanten serialisiert werden, kann nicht angepasst werden: Jede klassenspezifische writeObject , readObject , readObjectNoData , writeReplace et readResolve Methoden, die durch Enum-Typen definiert sind, werden bei der Serialisierung und Deserialisierung ignoriert. In ähnlicher Weise werden alle serialPersistentFields o serialVersionUID Felddeklarationen werden ebenfalls ignoriert - alle Aufzählungstypen haben einen festen serialVersionUID de 0L . Die Dokumentation von serialisierbaren Feldern und Daten für Aufzählungstypen ist nicht erforderlich, da es keine Variation im Typ der gesendeten Daten gibt.

Zitiert aus der Oracle-Dokumentation

Ein weiteres Problem mit konventionellen Singletons ist, dass man nach der Implementierung der Serializable Schnittstelle, bleiben sie nicht mehr singleton, weil die readObject() Methode immer eine neue Instanz zurück, wie ein Konstruktor in Java. Dies kann vermieden werden durch die Verwendung von readResolve() und verwirft die neu erstellte Instanz, indem sie durch ein Singleton wie unten ersetzt wird:

 // readResolve to prevent another instance of Singleton
 private Object readResolve(){
     return INSTANCE;
 }

Dies kann sogar noch komplexer werden, wenn Ihr Singleton-Klasse hält den Zustand aufrecht, da man sie transient machen muss, aber mit einem Enum Singleton wird die Serialisierung von der JVM garantiert.


Gute Lektüre

  1. Singleton-Muster
  2. Enums, Singletons und Deserialisierung
  3. Doppelt geprüfte Sperren und das Singleton-Muster

4voto

Nicolas Filotto Punkte 41176

So implementieren Sie eine einfache Einzelperson :

public class Singleton {
    // It must be static and final to prevent later modification
    private static final Singleton INSTANCE = new Singleton();
    /** The constructor must be private to prevent external instantiation */
    private Singleton(){}
    /** The public static method allowing to get the instance */
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

So erstellen Sie Ihr Singleton richtig faul:

public class Singleton {
    // The constructor must be private to prevent external instantiation
    private Singleton(){}
    /** The public static method allowing to get the instance */
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
    /**
     * The static inner class responsible for creating your instance only on demand,
     * because the static fields of a class are only initialized when the class
     * is explicitly called and a class initialization is synchronized such that only
     * one thread can perform it, this rule is also applicable to inner static class
     * So here INSTANCE will be created only when SingletonHolder.INSTANCE
     * will be called
     */
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
}

3voto

Onur Punkte 929

Sie benötigen die doppelte Überprüfung Idiom, wenn Sie die Instanzvariable einer Klasse träge laden müssen. Wenn Sie eine statische Variable oder ein Singleton träge laden müssen, benötigen Sie die Initialisierung auf Anfrage Halter Idiom.

Wenn das Singleton serialisierbar sein muss, müssen außerdem alle anderen Felder transient sein und die readResolve()-Methode muss implementiert werden, damit das Singleton-Objekt invariant bleibt. Andernfalls wird jedes Mal, wenn das Objekt deserialisiert wird, eine neue Instanz des Objekts erstellt. Die Methode readResolve() ersetzt das neue, mit readObject() gelesene Objekt, was dazu führt, dass dieses neue Objekt in den Müll wandert, da es keine Variable gibt, die sich auf dieses Objekt bezieht.

public static final INSTANCE == ....
private Object readResolve() {
  return INSTANCE; // Original singleton instance.
}

3voto

Shailendra Singh Punkte 445

Verschiedene Möglichkeiten, ein Singleton-Objekt zu erstellen:

  1. Gemäß Joshua Bloch - Enum wäre das Beste.

  2. Sie können auch eine Doppelkontrollsperre verwenden.

  3. Auch eine innere statische Klasse kann verwendet werden.

3voto

Dan Moldovan Punkte 381

Enum singleton

Der einfachste Weg, ein Singleton zu implementieren, das thread-sicher ist, ist die Verwendung einer Enum:

public enum SingletonEnum {
  INSTANCE;
  public void doSomething(){
    System.out.println("This is a singleton");
  }
}

Dieser Code funktioniert seit der Einführung von Enum in Java 1.5

Doppelt geprüfte Verriegelung

Wenn Sie ein "klassisches" Singleton programmieren wollen, das in einer Multithreading-Umgebung (ab Java 1.5) funktioniert, sollten Sie dieses verwenden.

public class Singleton {

  private static volatile Singleton instance = null;

  private Singleton() {
  }

  public static Singleton getInstance() {
    if (instance == null) {
      synchronized (Singleton.class){
        if (instance == null) {
          instance = new Singleton();
        }
      }
    }
    return instance;
  }
}

Dies ist vor 1.5 nicht thread-sicher, da die Implementierung des volatile-Schlüsselworts anders war.

Frühes Laden von Singleton (funktioniert auch vor Java 1.5)

Diese Implementierung instanziiert das Singleton, wenn die Klasse geladen wird, und bietet Thread-Sicherheit.

public class Singleton {

  private static final Singleton instance = new Singleton();

  private Singleton() {
  }

  public static Singleton getInstance() {
    return instance;
  }

  public void doSomething(){
    System.out.println("This is a singleton");
  }

}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X