2010-06-02 6 views
8

Ich komme mit dieser Frage bei der Implementierung Singleton-Muster in Java. Auch wenn das unten aufgeführte Beispiel nicht mein richtiger Code ist, aber dem Original sehr ähnlich ist.Wie zu synchronisieren statische Methode in Java

public class ConnectionFactory{ 
    private static ConnectionFactory instance; 

    public static synchronized ConnectionFactory getInstance(){ 
     if(instance == null){ 
      instance = new ConnectionFactory(); 
     } 

     return instance; 
    } 

    private ConnectionFactory(){ 
     // private constructor implementation 
    } 
} 

Weil ich über das Verhalten einer statischen synchronisierten Methode nicht ganz sicher bin, erhalte ich einen Vorschlag von Google - habe nicht (oder so wenig wie möglich) mehr statischen Synchron Methoden in der gleichen Klasse. Ich denke, wenn eine statische synchronisierte Methode implementiert wird, wird eine Sperre zum Klassenobjekt verwendet, so dass mehrere statische synchronisierte Methoden die Leistung des Systems beeinträchtigen können.

Bin ich richtig? oder verwendet JVM einen anderen Mechanismus zur Implementierung der statischen Synchronisierungsmethode? Was ist die beste Vorgehensweise, wenn ich mehrere statische synchronisierte Methoden in einer Klasse implementieren muss?

Danke euch allen!

Mit freundlichen Grüßen!

+2

Ist Ihr echten Code betrifft auch faul Initialisierung? Weil das normalerweise eine Verschwendung von Code und Entwicklerzeit ist; Das Feld in seiner Deklaration zu initialisieren ist in 99% der Fälle richtig und macht die Synchronisation überflüssig. –

Antwort

7

Der beste Ansatz (die so wenige Änderungen im Code wie möglich macht) ist wie dies zu tun:

public class ConnectionFactory{ 
    private static ConnectionFactory instance = new ConnectionFactory(); 

    public static ConnectionFactory getInstance(){ 
     return instance; 
    } 

    private ConnectionFactory(){ 
    } 
} 

Wie Sie sehen können, gibt es keine wirkliche Notwendigkeit, jetzt in getInstance Methode, so können Sie vereinfachen den Code:

public class ConnectionFactory{ 
    public static final ConnectionFactory INSTANCE = new ConnectionFactory(); 

    private ConnectionFactory(){ 
    } 
} 

UPD über Synchronisation: die beste Art und Weise auf eine Sperre synchronisiert, die nicht sichtbar äußeren Klassen, das heißt:

public class ConnectionFactory{ 
    private static final Object lock = new Object(); 

    public static void doSmth() { 
     synchronized (lock) { 

      ... 
     } 
    } 

    public static void doSmthElse() { 
     synchronized (lock) { 

      ... 
     } 
    } 
} 

Es gibt viele Diskussionen darüber, "warum auf this zu synchronisieren ist eine schlechte Idee" (wie this one), denke ich, dass das gleiche für die Synchronisierung auf Klasse ist.

+0

Wie würde es die 'Instanz 'erzeugen, wenn der einzige Konstruktor eine Ausnahme auslöst? – unbeli

+0

@unbeli: Es war mein schlechtes, korrigiert. Aber wenn Sie nicht einmal eine Instanz benötigen, wenn es eine korrekte Lösung war. – Roman

+0

@unbeli: durch Verwendung einer privaten statischen Factory-Methode oder eines statischen Initialisierungsblocks. Leider haben all diese Diskussionen über das Java-Speichermodell und die doppelte Überprüfung das Internet mit Hunderten von Codebeispielen belastet, die Neulingen den Eindruck vermitteln, dass das mühsame Initialisieren von Singletons in der Methode getInstance() tatsächlich eine gute Idee oder sogar die Norm ist. –

2

Ja, statische Methoden werden auf ihrem Klassenobjekt synchronisiert. Ich würde mir hier keine Gedanken über die Leistung machen, da dies wahrscheinlich nicht Ihr Leistungshighlight sein wird. Mach es einfach, optimiere wann und wo du es brauchst.

2

Statisch synchronisierte Methoden verwenden die Sperre für die Klasse. Im Fall Ihres Beispiels würde es auf die Sperre für das ConnectionFactory-Klassenobjekt zugreifen. Es empfiehlt sich, Schlösser nicht länger als nötig festzuhalten. Ob Sie mehrere synchronisierte Methoden haben, ist kein Problem für sich.

3

Es gibt verschiedene Möglichkeiten, ein Singleton zu erstellen.

Eine empfohlene Methode ist eine ENUM zu verwenden (garantiert nur eine Instanz erstellen):

public enum ConnectionFactory { 

    INSTANCE; 

} 

Oder Sie können es statisch erstellen, wenn die Klassen Lasten:

public class ConnectionFactory { 

    private static ConnectionFactory INSTANCE = new ConnectionFactory(); 

    private ConnectionFactory() {} 

    public static ConnectionFactory getInstance() { 
    return INSTANCE; 
    }  

} 

Wenn Sie müssen laden sie faul können Sie dieses Idiom verwenden (und nicht die double checked locking anti-pattern)

public class ConnectionFactory { 

    private static class ConnectionFactoryHolder { 
    private static ConnectionFactory INSTANCE = new ConnectionFactory(); 
    } 

    public static ConnectionFactory getInstance() { 
    return ConnectionFactoryHolder.INSTANCE; 
    } 

} 
0

Effektives Java empfiehlt die Verwendung von Enums zum Erstellen von Singleton.Also Sie Code würde wie folgt aussehen:

public enum ConnectionFactory{ 
INSTANCE; 

// Other factory methods go here. 

} 

}

Verwandte Themen