2010-03-17 10 views
6

Kürzlich besuchte ich einen Vortrag über einige Design-Muster:Inner Synchronisation auf das gleiche Objekt wie die äußere Synchronisation

Der folgende Code hatte angezeigt worden:

public static Singleton getInstance() 
{ 
    if (instance == null) 
    { 
    synchronized(Singleton.class) {  //1 
     Singleton inst = instance;   //2 
     if (inst == null) 
     { 
     synchronized(Singleton.class) { //3 
      inst = new Singleton();  //4 
     } 
     instance = inst;     //5 
     } 
    } 
    } 
    return instance; 
} 

entnommen aus: Double-checked locking: Take two

Meine Frage hat nichts mit dem oben genannten Muster zu tun, sondern mit den synchronisierten Blöcken:

Gibt es irgendwelche Vorteile für die doppelte Synchronisation in den Zeilen 1 & 3 in Bezug auf die Tatsache, dass der Synchronisationsvorgang auf dem gleichen Objekt durchgeführt wird?

Antwort

11

Im alten Java-Speichermodell (JMM) wurde beim Beenden eines synchronized Blocks die lokalen Daten in den Hauptspeicher ausgeleert. Eingabe eines synchronized-Blocks, der zum erneuten Lesen der zwischengespeicherten Daten führt. (Hier enthält der Cache Register mit zugehörigen Compiler-Optimierungen.) Der alte JMM war defekt und nicht korrekt implementiert.

Im neuen JMM tut es nichts. Neues JMM ist für 1.5 spezifiziert und für die "Sun" 1.4 JRE implementiert. 1.5 abgeschlossen ist es Ende des Dienstes Lebenszeit vor einiger Zeit, so dass Sie sich keine Sorgen über das alte JMM machen müssen (naja, vielleicht wird Java ME etwas Unvorhersehbares tun).

+1

ok ... könnten Sie bitte erläutern? Ich kann immer noch nicht den Nutzen des Obigen bekommen. – Yaneeve

+0

Bei der AFAIK-Synchronisierung wird immer noch gespült. (Siehe http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#synchronization) –

+0

Oh, ich habe gerade gemerkt, dass du über EXITING redest. Versäumt, dass –

2

Ich bin kein Speichermodell Experte, aber ich denke, man muss bedenken, dass ein "synchronisiert" nicht nur die Notwendigkeit signalisiert, eine Sperre zu erhalten, sondern auch Regeln über mögliche Optimierung von Code und Spülen und Auffrischen von Caches.

Hier finden Sie die Details in dem auf demselben Objekt synchronisieren zweimal Java Memory Model

+0

Das neue Java Memory Model befasst sich nicht mit dem Leeren von Caches. Es benutzt * happes-before * -Verhältnisse, die sich ziemlich unterscheiden. –

+1

Hmm, aber um eine solche Beziehung zu gewährleisten, muss eine Spülung der Cashes stattfinden. Oder zumindest so, dachte ich. Kannst du mich auf eine Ressource hinweisen, die den Unterschied/die Beziehung erklärt? –

2

finden erzwingt, dass alle der im Inneren des inneren Blocks Änderungen gerötete Speicher freigegeben wird, wenn der innere Synchronisationsblock verlassen wird. Aber es ist wichtig zu beachten, dass es keine Regeln gibt, die sagen, dass Änderungen, die nach dem inneren Synchronisationsblock gemacht wurden, nicht vorgenommen werden können, bevor die innere Synchronisation beendet wird.

Zum Beispiel

public void doSomething() 
{ 
    synchronized(this) { // "this" locked 
    methodCall1(); 
    synchronized(this) { 
     methodCall2(); 
    } // memory flushed 
    methodCall3(); 
    } // "this" unlocked and memory flushed 
} 

Kann in dieser Reihenfolge

public void doSomething() 
{ 
    synchronized(this) { // "this" locked 
    methodCall1(); 
    synchronized(this) { 
     methodCall2(); 
     methodCall3(); 
    } // memory flushed 
    } // "this" unlocked and memory flushed 
} 

Für eine detailliertere Erklärung überprüfen Double Check Locking im Ein Update auszuführen kompiliert werden, die nicht Abschnitt über eine funktioniert Drittel nach unten.