Frage

Warum wird das Muster dann als gebrochen? Es sieht gut aus für mich? Irgendwelche Ideen?

public static Singleton getInst() {
    if (instace == null) createInst();
    return instace;
}

private static synchronized createInst() {
     if (instace == null) {
         instace = new Singleton(); 
     }
}
War es hilfreich?

Lösung

Es sieht auf den ersten Blick in Ordnung, aber diese Technik hat viele subtile Probleme und in der Regel vermieden werden sollte. Betrachten wir zum Beispiel die folgende Sequenz von Ereignissen:

  1. Thread A bemerkt, dass der Wert nicht initialisiert, so erhält er die sperren und beginnt die initialisieren Wert.
  2. Der vom Compiler erzeugte Code ist erlaubt die gemeinsam genutzte Variable zu aktualisieren Punkt zu einer teilweise konstruierten Objekt vor A beendet Durchführen der Initialisierung.
  3. Thread B bemerkt, dass die gemeinsame Variable initialisiert worden ist (oder so es erscheint), und gibt seinen Wert zurück. Da Thread B glaubt den Wert bereits initialisiert ist, tut es nicht erwerben die Sperre. Wenn B verwendet die Objekt, bevor alle die Initialisierung von A erfolgt gesehen durch B wird das Programm wahrscheinlich zum Absturz bringen.

Sie können dies vermeiden, indem Sie das „flüchtige“ Schlüsselwort Ihre Singleton Instanzen korrekt verarbeiten

Andere Tipps

Die ganze Diskussion ist eine riesige, endlose Verschwendung von Gehirn Zeit. 99,9% der Zeit, Singletons haben keine wesentlichen Rüstkosten und es gibt keinen Grund für erfundene Setups unsynchronisierten garantierter verzögertes Laden zu erreichen.

Dies ist, wie Sie einen Singleton in Java schreiben:

public class Singleton{
    private Singleton instance = new Singleton();
    private Singleton(){ ... }
    public Singleton getInstance(){ return instance; }
}

Noch besser wäre es, macht es zu einem Enum:

public enum Singleton{
    INSTANCE;
    private Singleton(){ ... }
}

Ich weiß nicht, ob es gebrochen ist, aber es ist nicht wirklich die effizienteste Lösung ist aufgrund Synchronisierungs, die ziemlich teuer ist. Ein besserer Ansatz wäre, die ‚Initialisierung On Demand-Halter Idiom‘ verwenden, die Ihre Singleton in den Arbeitsspeicher lädt das erste Mal, es wird gefordert, wie der Name schon sagt, so verzögertes Laden. Der größte Vorteil, den Sie mit diesem Idiom erhalten ist, dass Sie nicht zu synchronisieren brauchen, weil die JLS sorgt dafür, dass das Laden von Klassen Serien ist.

Detaillierte Wikipedia-Eintrag zum Thema: http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom

Eine andere Sache im Auge zu behalten ist, dass da Dependency Injection Frameworks wie Spring und Guice entstanden, Klasseninstanzen von diesen Containern erstellt und verwaltet erstellt werden, und sie werden Sie mit einem Singleton liefern, falls gewünscht, so ist es nicht wert brechen Sie den Kopf über sie, es sei denn, Sie Idee hinter dem Muster lernen wollen, was nützlich ist. Beachten Sie auch, dass durch diese IOC-Container sind Singletons pro Container-Instanz bereitgestellt Singletons, aber in der Regel werden Sie einen IOC-Container pro Anwendung, so dass es kein Problem werden zu lassen.

Das Problem ist folgendes: Ihre JVM Code neu anordnen kann und Felder sind nicht immer gleich für verschiedene Themen. Werfen Sie einen Blick auf diese: http://www.ibm.com/ developer / java / library / j-dcl.html . Die Verwendung des flüchtigen Schlüsselwort soll dieses Problem zu beheben, aber es ist gebrochen, bevor Java 1.5.

Die meiste Zeit einzeln geprüfte Verriegelung ist mehr als schnell genug, versuchen Sie dies:

// single checked locking: working implementation, but slower because it syncs all the time
public static synchronized Singleton getInst() {
    if (instance == null) 
        instance = new Singleton();
    return instance;
}

auch einen Blick auf effektive Java hat, wo Sie ein großes Kapitel zu diesem Thema finden.

Dieses zusammenfassen:. Dont Sie doppelte Verriegelung überprüft, gibt es bessere idoms

Initialisierung On Demand Halter Idiom , yup, das es ist:

public final class SingletonBean{

    public static SingletonBean getInstance(){
        return InstanceHolder.INSTANCE;
    }

    private SingletonBean(){}

    private static final class InstanceHolder{
        public static final SingletonBean INSTANCE = new SingletonBean();
    }

}

Obwohl Joshua Bloch auch das Muster Singleton Enum empfiehlt in Effective Java Kapitel 2, Punkt 3:

// Enum singleton - the prefered approach
public enum Elvis{
    INSTANCE;
    public void leaveTheBuilding(){ ... }
}

Das ist Ihre Frage nicht beantworten (andere bereits getan haben), aber ich möchte Sie mit Singletons / faul initialisierte Objekte meiner Erfahrung sagen:

Wir hatten ein paar Singletons in unserem Code. Einmal hatten wir einen Konstruktorparameter einen Singleton hinzuzufügen und hatten ein ernstes Problem, da der Konstruktor dieser Singleton auf dem Getter aufgerufen wurde. Es wurden nur folgende Möglichkeiten:

  • stellt ein statisches Getter (oder ein anderes Singleton) für das Objekt, das benötigt wurde diesen Singleton zu initialisieren,
  • passieren das Objekt die Singletons als Parameter für die Getter oder
  • initialisieren
  • get des Singletons befreien, indem Instanzen um vorbei.

Schließlich war die letzte Option, den Weg zu gehen. Nun initialisieren wir alle Objekte auf Anwendungsstart und Pass Instanzen um erforderlich (vielleicht als eine kleine Schnittstelle). Wir haben diese Entscheidung nicht bereut, weil

  • die Abhängigkeiten von einem Stück Code ist kristallklar,
  • können wir unseren Code viel einfacher testen, indem Dummy-Implementierungen der benötigten Objekte bereitstellt.

Die meisten Antworten sind hier richtig, warum es gebrochen ist, aber falsch oder was darauf hindeutet, zweifelhafte Strategien für eine Lösung.

Wenn Sie wirklich, wirklich muss einen Singleton verwenden (was in den meisten Fällen Sie sollte nicht , da es zerstört Testbarkeit, kombiniert Logik, wie eine Klasse mit dem konstruieren Klasse des Verhalten, die Klassen Würfe, die die Singleton mit dem Wissen nutzen, wie man zu erhalten, und führt zu spröder Code) und sind über die Synchronisation betrifft, ist die richtige Lösung für die Verwendung eine statische Initialisierer instantiate die Instanz.

private static Singleton instance = createInst();

public static Singleton getInst() {
    return instance ;
}

private static synchronized createInst() {
    return new Singleton(); 
}

Die Spezifikation garantiert Java-Sprache, dass statischer initiailzers nur einmal ausgeführt werden, wenn eine Klasse zum ersten Mal geladen wird, und in einer garantierten Thread-sichere Weise.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top