Frage

Ich versuche, ein Problem in unserem System aufzuspüren und der folgende Code macht mir Sorgen.

: Die folgenden Ereignisse eintritt in unserer doPost () -Methode in der primären Servlet (Name die Schuldigen zu schützen geändert wurde)
...
if(Single.getInstance().firstTime()){
   doPreperations();
}
normalResponse();
...

Die Singleton 'Single' sieht wie folgt aus:

private static Single theInstance = new Single();

private Single() {
...load properties...
}

public static Single getInstance() {
    return theInstance;
}

Mit der Möglichkeit, dies festgelegt ist eine statische Initialisierer zu verwenden, anstatt in dem getInstance () -Methode für ein Null-theInstance Überprüfung, könnte dies überfährt wieder aufgebaut und immer wieder?

PS - Wir laufen WebSphere 6 mit der App auf Java 1.4

War es hilfreich?

Lösung

Das fand ich auf dem Sun-Website:

  

Multiple Singletons Gleichzeitig Geladen durch Different Class Lader

     

Wenn zwei Klassenlader eine Klasse zu laden,   Sie haben tatsächlich zwei Kopien der   Klasse, und jeder kann seine eigene haben   Singleton-Instanz. Das ist   besonders relevant in Servlets   läuft in bestimmten Servlet-Engines   (IPlanet- zum Beispiel), wobei jeder   Servlet verwendet standardmäßig eine eigene Klasse   Lader. Zwei verschiedene Servlets   Zugriff auf eine gemeinsame Singleton wird, in   Tatsächlich bekommt zwei verschiedene Objekte.

     

Mehrere Klassenlader auftreten mehr   gemeinhin als Sie vielleicht denken. Wann   Browser Belastungsklassen aus dem Netz   für die Verwendung von Applets, die sie verwenden ein   separater Klassenlader für jeden Server   Adresse. In ähnlicher Weise Jini und RMI   Systeme können eine separate Klasse verwenden   Lader für die verschiedenen Codebasen   von denen herunterladen sie Klassendateien.   Wenn Ihr eigenes System verwendet benutzerdefinierte Klasse   Auflader, alle die gleichen Probleme können   entstehen.

     

Wenn durch verschiedene Klassenlader geladen,   zwei Klassen mit dem gleichen Namen, sogar   die gleichen Paketnamen, werden behandelt, als   distinct - auch, wenn in der Tat, sie sind   Byte-für-Byte die gleiche Klasse. Das   verschiedene Klassenlader darstellen   verschiedene Namensräume, die unterscheiden   Klassen (auch wenn die Klassen   Namen sind gleich), so dass die beiden   MySingleton Klassen sind in der Tat   deutlich. (Siehe „Klasse Lader als   Namespace-Mechanismus“in Ressourcen).   Da zwei Singleton Objekte gehören zu   zwei Klassen mit dem gleichen Namen, wird es   erscheinen auf den ersten Blick, dass es   zwei Singleton Objekte der gleichen   Klasse.

Citation .

Neben dem oben genannten Problem, wenn firstTime() nicht synchronisiert ist, könnten Sie es Threadingprobleme haben auch.

Andere Tipps

Nein, es wird nicht bekommen gebaut immer und immer wieder. Es ist statisch, so wird es nur einmal gebaut werden, oder wenn die Klasse zum ersten Mal durch den Classloader berührt wird.

Einzige Ausnahme -., Wenn Sie mehrere Klassenlader haben passieren

(von GeekAndPoke ):

alt text

Wie andere erwähnt haben, wird die statische Initialisierung nur einmal pro Classloader ausgeführt werden.

Eine Sache, die ich auf einen Blick würde, ist die firstTime() Methode - warum kann nicht das Werk in doPreparations() innerhalb der Singleton behandelt wird selbst

?

Klingt wie ein böser Satz von Abhängigkeiten.

Es gibt absolut keinen Unterschied zwischen einer statischen Initialisierer und faul Initialisierung verwenden. In der Tat ist es viel einfacher zu vermasseln die verzögerte Initialisierung, die auch die Synchronisation erzwingt. Die JVM gewährleistet, dass der statische Initialisierer wird immer ausgeführt werden, bevor die Klasse zugegriffen wird, und es wird einmal und nur einmal vorkommen.

Das heißt JVM nicht garantieren, dass Ihre Klasse wird nur einmal geladen werden. sieht jedoch immer noch, auch wenn es mehr als einmal geladen ist, wird Ihre Web-Anwendung nur die relevante Singleton, da sie entweder in den Web-Anwendung oder Classloader seiner Eltern geladen. Wenn Sie mehr Web-Anwendung bereitgestellt haben, dann firsttime () wird einmal für jede Anwendung aufgerufen werden.

Die auffälligsten Dinge zu überprüfen sind, dass firsttime () synchronisiert werden muss, und dass der erstmalige Flag gesetzt, bevor diese Methode verlassen.

Nein, es wird nicht mehrere Kopien von ‚Single‘ erstellen. (Classloader Problem wird später besucht werden)

Die Implementierung Sie skizziert wird als 'Eager Initialisierung' durch in Briant Goetz Buch beschrieben - ‚ Java Concurrency in der Praxis ‘.

public class Single
{
    private static Single theInstance = new Single();

    private Single() 
    { 
        // load properties
    }

    public static Single getInstance() 
    {
        return theInstance;
    }
}

Allerdings ist der Code nicht Sie wollen. Ihr Code versucht, faul-Initialisierung durchzuführen, nachdem die Instanz erstellt wird. Dies erfordert alle Client-Bibliothek ‚firsttime () / doPreparation ()‘, bevor Sie es ausführen. Sie werden auf dem Client verlassen, rechts, was den Code sehr zerbrechlich machen zu tun.

Sie können den Code wie folgt ändern, so wird es keine doppelten Code sein.

public class Single
{
    private static Single theInstance = new Single();

    private Single() 
    { 
        // load properties
    }

    public static Single getInstance() 
    {   
        // check for initialization of theInstance
        if ( theInstance.firstTime() )
           theInstance.doPreparation();

        return theInstance;
    }
}

Leider ist dies eine schlechte Umsetzung verzögerte Initialisierung und dies wird in Umgebung mit gemeinsamer Zugriff (wie J2EE-Container) nicht funktionieren.

Es gibt viele Artikel über Singleton Initialisierung geschrieben, speziell auf Speichermodell. JSR 133 viele Schwächen in Java Speicher adressiert Modell in Java 1.5 und 1.6.

Mit Java 1.5 und 1.6, haben Sie mehrere Möglichkeiten, und sie sind in dem Buch erwähnt ‚ Effective Java ‘von Joshua Bloch.

  1. Eager Initialziation, wie die oben [EJ Artikel 3]
  2. Faul initialisiert Halter Klasse Idiom [EJ Artikel 71]
  3. Enum-Typ [EJ Artikel 3]
  4. Double Checked Locking mit 'volatilem' statischem Feld [EJ Artikel 71]

Lösung 3 und 4 nur in Java 1.5 oder höher verwendet. So ist die beste Lösung wäre, # 2.

Hier ist die psuedo-Implementierung.

public class Single
{
    private static class SingleHolder
    {
        public static Single theInstance = new Single();
    }

    private Single() 
    { 
        // load properties
        doPreparation();
    }

    public static Single getInstance() 
    {
        return SingleHolder.theInstance;
    }
}

Beachten Sie, dass ‚doPreparation ()‘ innerhalb des Konstruktors ist, so dass Sie garantiert sind, um die richtig initialisiert Instanz zu erhalten. Auch Sie sind piggying auf JVM faul Klasse Laden zurück und brauchen keine Synchronisation ‚getInstance ()‘.

Eine Sache, Sie bemerken, dass statisches Feld theInstance ist nicht ‚endgültig‘. Das Beispiel auf Java Concurrency hat nicht ‚endgültig‘ aber EJ tut. Vielleicht kann James mehr Farbe in seine Antwort auf ‚Classloader‘ und Anforderung der ‚endgültigen‘ hinzufügen Korrektheit zu gewährleisten,

Having said that, gibt es einen Nebeneffekt, dass bei der Verwendung von 'static final'. Java-Compiler ist sehr aggressiv, wenn es ‚static final‘ sieht und versucht, es so weit wie möglich Inline. Dies wird auf .

Hier ist ein einfaches Beispiel.

Datei: A.java

public class A
{
    final static String word = "Hello World";
}

Datei: B.java

public class B
{
    public static void main(String[] args) {
        System.out.println(A.word);
    }
}

Nachdem Sie beide A.java und B.java kompilieren, ändern Sie A.java zu folgen.

Datei: A.java

public class A
{
    final static String word = "Goodbye World";
}

Sie neu kompilieren 'A.java' und Rerun B.class. Die Ausgabe, die Sie erhalten würden, ist

Hello World

Wie für die Klassenlader Frage, die Antwort ja ist, können Sie mehr als eine Instanz von Singleton in mehreren Classloader haben. Sie können weitere Informationen über wikipedia finden. Es gibt auch einen spezifischen Artikel über Websphere .

Das einzige, was ich, dass Singleton Implementierung ändert etwa würde (außer keinen Singleton überhaupt verwendet wird) ist das Instanzenfeld endgültig zu machen. Das statische Feld wird einmal initialisiert wird, auf Klasse Last. Da Klassen lazily geladen werden, erhalten Sie effektiv faul Instanziierung kostenlos.

Natürlich, wenn es aus separaten Klassenlader geladen werden erhalten Sie mehrere „Singletons“, aber das ist eine Einschränkung jeden Singleton Idiom in Java.

Bearbeiten : die erstmalige () und doPreparations () Bits obwohl Verdächtigen suchen. Können sie nicht in den Konstruktor der Singleton-Instanz verschoben werden?

Nein - die statische Initialisierung des instance wird immer nur einmal durchgeführt werden. Zwei Dinge zu beachten:

  • Dies ist nicht Thread-sicher (die Instanz nicht „veröffentlicht“ in dem Hauptspeicher)
  • Ihre firstTime Methode wird wahrscheinlich mehrmals aufgerufen, es sei denn, richtig synchronisiert

In der Theorie wird es nur einmal gebaut werden. Allerdings bricht dieses Muster in verschiedenen Anwendungsservern, in denen Sie mehrere Instanzen von ‚Singleton‘ Klassen erhalten können (da sie nicht Thread-sicher).

Auch hat die Singletonmuster viel kritisiert worden. Siehe zum Beispiel Singleton ich liebe dich, aber Sie bringen mich runter

Dies wird nur einmal erhalten geladen, wenn die Klasse durch den Klassenlader geladen wird. Dieses Beispiel bietet eine bessere Singleton Implementierung jedoch, es ist so faul-geladen wie möglich und Thread-sicher. Darüber hinaus arbeitet es in allen bekannten Versionen von Java. Diese Lösung ist die portable über verschiedene Java-Compiler und virtuelle Maschinen.


public class Single {

private static class SingleHolder {
   private static final Single INSTANCE = new Single();
}

private Single() {
...load properties...
}

public static Single getInstance() {
    return SingleHolder.INSTANCE;
}

}

Die innere Klasse wird nicht früher verwiesen (und daher geladen nicht früher von dem Klassenlader) als der Moment, die getInstance () aufgerufen wird. Somit ist diese Lösung threadsicher ohne spezielle Sprachkonstrukte zu erfordern (d.h. flüchtigen und / oder synchronisiert).

Es ist nicht zwingend notwendig für die einzelne Instanz endgültig zu sein (es ist keine gute Idee, überhaupt in der Tat, denn das man es Verhalten mit anderen Mustern wechseln wird vermieden).

In dem folgenden Code können Sie sehen, wie es nur einmal instanziiert wird (erste Mal, wenn Sie den Konstruktor aufrufen)

Paket Datum;

import java.util.Date;

public class USDateFactory implementiert DateFactory {     private static USDateFactory usdatefactory = null;

private USDateFactory () { }

public static USDateFactory getUsdatefactory() {
    if(usdatefactory==null) {
        usdatefactory = new USDateFactory();
    }
    return usdatefactory;
}

public String getTextDate (Date date) {
    return null;
}

public NumericalDate getNumericalDate (Date date) {
    return null;
}

}

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