it-swarm.com.de

Java Singleton und Synchronisation

Bitte klären Sie meine Fragen zu Singleton und Multithreading:

  • Was ist der beste Weg, um Singleton in Java in einer Multithread-Umgebung Zu implementieren?
  • Was passiert, wenn mehrere Threads gleichzeitig auf die Methode getInstance() Zugreifen möchten?
  • Können wir Singletons getInstance()synchronized machen?
  • Ist bei der Verwendung von Singleton-Klassen wirklich eine Synchronisation erforderlich?
100
RickDavis

Ja, das ist notwendig. Es gibt verschiedene Methoden, um die Thread-Sicherheit bei der verzögerten Initialisierung zu erreichen:

Draconische Synchronisation:

private static YourObject instance;

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

Diese Lösung erfordert, dass jeder -Thread synchronisiert wird, wenn in der Realität nur die ersten sein müssen.

Doppelte Checksynchronisation :

private static final Object lock = new Object();
private static volatile YourObject instance;

public static YourObject getInstance() {
    YourObject r = instance;
    if (r == null) {
        synchronized (lock) {    // While we were waiting for the lock, another 
            r = instance;        // thread may have instantiated the object.
            if (r == null) {  
                r = new YourObject();
                instance = r;
            }
        }
    }
    return r;
}

Diese Lösung stellt sicher, dass nur die ersten Threads, die versuchen, Ihren Singleton zu erwerben, den Vorgang des Erfassens der Sperre durchlaufen müssen.

Initialisierung bei Bedarf :

private static class InstanceHolder {
    private static final YourObject instance = new YourObject();
}

public static YourObject getInstance() {
    return InstanceHolder.instance;
}

Diese Lösung nutzt die Garantien des Java-Speichermodells für die Klasseninitialisierung, um Thread-Sicherheit zu gewährleisten. Jede Klasse kann nur einmal geladen werden und wird nur dann geladen, wenn sie benötigt wird. Das bedeutet, dass beim ersten Aufruf von getInstanceInstanceHolder geladen und instance erstellt wird. Da dies von ClassLoaders gesteuert wird, ist keine zusätzliche Synchronisation erforderlich.

190
Jeffrey

Dieses Muster bewirkt eine Thread-sichere Lazy-Initialisierung der Instanz ohne explizite Synchronisation!

public class MySingleton {

     private static class Loader {
         static final MySingleton INSTANCE = new MySingleton();
     }

     private MySingleton () {}

     public static MySingleton getInstance() {
         return Loader.INSTANCE;
     }
}

Es funktioniert, weil es den Class Loader verwendet, um die Synchronisierung für Sie kostenlos durchzuführen: Auf die Klasse MySingleton.Loader wird zuerst innerhalb der getInstance()-Methode zugegriffen, so dass die Loader-Klasse beim ersten Aufruf von getInstance() geladen wird. Außerdem garantiert der Klassenlader, dass alle statischen Initialisierungen abgeschlossen sind, bevor Sie auf die Klasse zugreifen können. Dies gibt Ihnen Thread-Sicherheit.

Es ist wie Magie.

Es ist tatsächlich dem Enumerationsmuster von Jhurtado sehr ähnlich, aber ich finde das Enumerationsmuster als Missbrauch des Enumerationskonzepts (obwohl es funktioniert).

61
Bohemian

Wenn Sie in einer Multithread-Umgebung in Java arbeiten und sicherstellen müssen, dass alle Threads auf eine einzelne Instanz einer Klasse zugreifen, können Sie ein Enum verwenden. Dies hat den zusätzlichen Vorteil, dass Sie die Serialisierung leichter durchführen können.

public enum Singleton {
    SINGLE;
    public void myMethod(){  
    }
}

und dann müssen Ihre Threads Ihre Instanz wie folgt verwenden:

Singleton.SINGLE.myMethod();
22
jhurtado

Ja, Sie müssen getInstance() synchronisieren. Wenn dies nicht der Fall ist, kann eine Situation auftreten, in der mehrere Instanzen der Klasse erstellt werden können. 

Betrachten Sie den Fall, in dem Sie zwei Threads haben, die gleichzeitig getInstance() aufrufen. Nun stellen Sie sich vor, dass T1 unmittelbar nach der instance == null-Prüfung ausgeführt wird und T2 ausgeführt wird. Zu diesem Zeitpunkt ist die Instanz nicht erstellt oder festgelegt, sodass T2 die Prüfung besteht und die Instanz erstellt. Stellen Sie sich nun vor, dass die Ausführung wieder auf T1 wechselt. Nun ist der Singleton erstellt, aber T1 hat die Prüfung bereits durchgeführt! Das Objekt wird erneut erstellt! Durch das Synchronisieren von getInstance() wird dieses Problem vermieden.

Es gibt einige Möglichkeiten, Singletons threadsicher zu machen, aber die Synchronisierung von getInstance() ist wahrscheinlich die einfachste.

8
Oleksi

Enum Singleton

Die einfachste Methode zum Implementieren eines Singleton-Threads ist die Verwendung eines Enums

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

Doppelte überprüfte Verriegelung

Wenn Sie ein "klassisches" Singleton codieren möchten, das in einer Multithread-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 threadsicher, da die Implementierung des volatilen Schlüsselworts unterschiedlich war.

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

Diese Implementierung instanziiert den 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");
  }

}
6
Dan Moldovan

Sie können auch einen statischen Codeblock verwenden, um die Instanz beim Laden der Klasse zu instanziieren und Probleme mit der Thread-Synchronisierung zu vermeiden.

public class MySingleton {

  private static final MySingleton instance;

  static {
     instance = new MySingleton();
  }

  private MySingleton() {
  }

  public static MySingleton getInstance() {
    return instance;
  }

}
2
usha

Wie implementiere ich Singleton am besten in Java in einer Multithread-Umgebung?

In diesem Beitrag erfahren Sie, wie Sie Singleton am besten implementieren können.

Was ist ein effizienter Weg, um ein Singleton-Muster in Java zu implementieren?

Was passiert, wenn mehrere Threads versuchen, gleichzeitig auf die getInstance () - Methode zuzugreifen?

Dies hängt von der Art und Weise ab, wie Sie die Methode implementiert haben. Wenn Sie die doppelte Verriegelung ohne flüchtige Variable verwenden, erhalten Sie möglicherweise ein teilweise konstruiertes Singletonobjekt.

Weitere Informationen finden Sie in dieser Frage:

Warum wird in diesem Beispiel der flüchtigen Verriegelung die Volatilität verwendet

Können wir getInstance () von singleton synchronisieren?

Ist bei der Verwendung von Singleton-Klassen wirklich eine Synchronisation erforderlich?

Nicht erforderlich, wenn Sie den Singleton auf folgende Weise implementieren

  1. statische Intitalisierung
  2. enum 
  3. LazyInitalaization mit Initialization-on-demand_holder_idiom 

Weitere Informationen finden Sie in dieser Frage

Java Singleton Design Pattern: Fragen

0
Ravindra babu
public class Elvis { 
   public static final Elvis INSTANCE = new Elvis();
   private Elvis () {...}
 }

Quelle: Effektives Java -> Punkt 2 

Es empfiehlt sich, es zu verwenden, wenn Sie sicher sind, dass die Klasse immer Singleton bleibt. 

0
Ashish