DoubleCheckedLocking

Status
Nicht offen für weitere Antworten.

enriico

Mitglied
Das Double-checked locking soll ja angeblich den Zugriff auf die Instanziierung mittels einer zweiten Bedingung schützen. Das soll sicherstellen, dass die Instanziierung nur durchgeführt wird, wenn wirklich noch keine Instanz angelegt wurde.

Das könnte doch funktionieren... wäre da nicht das Speichermodell der Java-Plattform! Die zweite Bedingung if (instance == null) kann nämlich zu true evaluieren, ohne dass new DoubleCheckedLockingSingleton() aufgerufen und das instanziierte Objekt dem Klassenattribut instance zugewiesen wurde!

Um das exemplarisch zu verdeutlichen, zeige ich den Pseudo-Bytecode für den Befehl instance = new DoubleCheckedLockingSingleton() an:

1.// Speicher alloziieren
ptrMemory = allocateMemory()
2.// Den Speicher dem Klassenattribut zuweisen, ab hier gilt: instance != null
assignMemory(instance, ptrMemory)
3.// Den Konstruktor aufrufen, das Objekt ist dann ab hier korrekt instanziiert
callDoubleCheckedLockingSingletonConstructor(instance)

Zwischen der zweiten und dritten Zeile könnte die Ausführung des Threads durch die Java Virtual Machine unterbrochen, und die Ausführung eines zweiten Threads vorgezogen werden. Die zweite Bedingung if (instance == null) würde damit zu true evaluieren, ohne dass bisher der Konstruktor (Zeile 3) aufgerufen worden wäre.
Das double-checked locking ist damit nicht sicher und die mögliche Lösung dafür auch nicht oder sehe ich das falsch?

-------------------------------------------------------------------------------------------------------------------------
//is bad
Code:
public class v5_DoubleCheckedLockingSingleton {
   private static v5_DoubleCheckedLockingSingleton instance = null;
   private v5_DoubleCheckedLockingSingleton() {}

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

//should be good
Code:
public class ThreadLocalDCL {
   private static ThreadLocal<Boolean> initHolder = new ThreadLocal<Boolean>();
   private static ThreadLocalDCL instance = null;
      public static ThreadLocalDCL getInstance() {
       System.out.println(Thread.currentThread().getName() + " " + initHolder.get());
       if (initHolder.get() == null){
           synchronized (ThreadLocalDCL.class) {
               if (instance == null) {
                   instance = new ThreadLocalDCL();
               }
               initHolder.set(Boolean.TRUE);
           }
       }
       System.out.println(Thread.currentThread().getName() + " " + initHolder.get());
       return instance;
   }
}
 

enriico

Mitglied
herzlichen dank für deine antwort,
ich frage mich einfach, ist die von mir gepostete lösung thread safe?

die seite konnte mir leider darauf keine antwort geben
 

enriico

Mitglied
ich konnte das problem erkennen oder habe nun die bestätigung, dass meine gute variante das problem des doublecheckedlocking problem löst.

enriico hat gesagt.:
-------------------------------------------------------------------------------------------------------------------------
//is bad
Code:
public class v5_DoubleCheckedLockingSingleton {
   private static v5_DoubleCheckedLockingSingleton instance = null;
   private v5_DoubleCheckedLockingSingleton() {}

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

ich gehe davon aus, dass zwei verschiedene threads die instanz holen wollen und zwar
zeige ich es euch an diesem ablaufschema.

der erste thread betritt die methode getInstance() und die erste if-bedingung ergibt true,
da jo noch kein thread vor ihm eine instanz geholt hat. anschliessend wir die klasse
v5_DoubleCheckedLockingSingleton.class gelockt und der erste thread gelangt zur zweiten if-bedingung.
auch diese bedingung ergibt true und der thread gelangt zur instanzierung. das java memory
model besagt, dass das instanzieren in drei schritten erfolgt.

1.// Speicher alloziieren
ptrMemory = allocateMemory()
2.// Den Speicher dem Klassenattribut zuweisen, ab hier gilt: instance != null
assignMemory(instance, ptrMemory)
3.// Den Konstruktor aufrufen, das Objekt ist dann ab hier korrekt instanziiert
callDoubleCheckedLockingSingletonConstructor(instance)

thread 1 hat nun die ersten beiden punkte erfolgreich gemacht und in diesem moment findet
eine thread-umschaltung statt. ein zweiter thread betritt die methode und gelangt zur if-bedingung.
diese ergibt false, da der erste thread den speicher bereits dem klassenattribut zugewiesen hat.
thread 2 erhält nun ein fehlerhaftes instance objekt, da ja der konstruktor noch nicht ausgeführt
werden konnte.


enriico hat gesagt.:
//should be good
Code:
public class ThreadLocalDCL {
   private static ThreadLocal<Boolean> initHolder = new ThreadLocal<Boolean>();
   private static ThreadLocalDCL instance = null;
      public static ThreadLocalDCL getInstance() {
       System.out.println(Thread.currentThread().getName() + " " + initHolder.get());
       if (initHolder.get() == null){
           synchronized (ThreadLocalDCL.class) {
               if (instance == null) {
                   instance = new ThreadLocalDCL();
               }
               initHolder.set(Boolean.TRUE);
           }
       }
       System.out.println(Thread.currentThread().getName() + " " + initHolder.get());
       return instance;
   }
}
diese variante löst das problem des DoubleCheckedLocking sauber, da jeder Thread der
diese Methode zum ersten mal betritt, die erste if-bedingung passiert...
 
Status
Nicht offen für weitere Antworten.

Neue Themen


Oben