2017-01-26 5 views
0

ich zur Zeit über Intrinsic Locks and Synchronization auf oracle.com lese, wo ich zu diesem besonderen Beispiel kam:Intrinsic Schlösser und Synchronisation

Synchronisierte Aussagen sind auch nützlich für die Gleichzeitigkeit mit feinkörnigem Synchronisation zu verbessern. Angenommen, die Klasse MsLunch hat beispielsweise zwei Instanzfelder, c1 und c2, die niemals zusammen verwendet werden. Alle Updates dieser Felder müssen synchronisiert werden, aber es gibt keinen Grund zu verhindern, dass eine Aktualisierung von c1 mit einer Aktualisierung von c2 verschachtelt wird - und dies reduziert die Nebenläufigkeit, indem eine unnötige Blockierung erzeugt wird. Anstatt synchronisierte Methoden zu verwenden oder die damit verbundene Sperre anderweitig zu verwenden, erstellen wir zwei Objekte, um nur Sperren bereitzustellen.

public class MsLunch { 
    private long c1 = 0; 
    private long c2 = 0; 
    private Object lock1 = new Object(); 
    private Object lock2 = new Object(); 

    public void inc1() { 
     synchronized(lock1) { 
      c1++; 
     } 
    } 

    public void inc2() { 
     synchronized(lock2) { 
      c2++; 
     } 
    } 
} 

Vor diesem Abschnitt synchronized Verfahren, in denen erklärt:

public synchronized void increment() { 
    this.c++; 
} 

Welche sein sollte, und mir bitte korrigieren, wenn ich falsch bin, das gleiche wie

public void increment() { 
    synchronized(this) { 
     c++; 
    } 
} 

wenn Ich füge keine Funktionalität zu increment() hinzu, ist das richtig?

Meine Frage ist jetzt aus dem Satz kommt:

aber es gibt keinen Grund, ein Update von c1 zu verhindern, dass verschachtelte mit einem Update von c2

sein Ich bin nicht sicher, ob ich vollständig verstehen, was "interleaved" bedeutet in diesem Zusammenhang. Bedeutet es, dass wenn ich z.B. entfernen lock2 aus dem MsLunch Beispiel:

public class MsLunch { 
    private long c1 = 0; 
    private long c2 = 0; 
    private Object lock1 = new Object(); 
    // private Object lock2 = new Object(); // 'lock2' is no more! 

    public void inc1() { 
     synchronized(lock1) { 
      c1++; 
     } 
    } 

    public void inc2() { 
     synchronized(lock1) { // Using 'lock1' here too 
      c2++; 
     } 
    } 
} 

ich in Schwierigkeiten mit Sperren bekommen? Sagen thread-1 läuft in , erhält die Sperre von lock1, aber wird ausgesetzt, bevor in der Lage sein, die Sperre zu erhöhen oder zu lösen. Jetzt thread-2 wird inc2() eingeben, wo eine andere Sperre für lock1 erstellt wird. Wird das vermieden, indem ein anderer lock2 verwendet wird und ist das der Grund, warum ich nicht einfach this als Lock-Provider verwenden würde? Oder mit anderen Worten: Kann das ein Problem verursachen?

+0

Nein, Sie können nicht in * Schwierigkeiten * geraten, Sie werden nur unnötigerweise verhindern, dass 'c1' und' c2' gleichzeitig erhöht werden, da sie die gleiche Sperre teilen (egal ob 'this' oder a Trennen Sie 'lock1') und haben Sie daher eine Abhängigkeit zwischen ihnen durch die Sperre. – Kayaman

+0

@Kayaman Oh, die deutsche Übersetzung von "interleaved" ist so etwas wie "ineinander" oder "ineinander", also bin ich ein bisschen verwirrt. Aber warum verhindert das gleichzeitig "c1" und "c2"? Wenn 'lock1' im Beispiel' lock1' nur eine Sperre "* anywhere *" im Code enthält, bedeutet das, dass es auch anderswo blockiert wird? So muss 'thread-2' warten, bis' thread-1' '' c1' 'aktualisiert, bevor '2' aktualisiert werden kann. Das bedeutet auch, dass jedes Objekt nur eine einzige Sperre zur gleichen Zeit bereitstellen kann - das war mir beim Lesen des Kapitels nicht klar. – displayname

+0

Ja, jedes Objekt bietet eine Sperre nach der anderen. Das ist die ganze Idee, warum synchronisiert so funktioniert. – Kayaman

Antwort

2

Zwei Schlösser hier nur um die Möglichkeit zu haben, c1 und c2 unabhängig zu erhöhen und nicht zu warten, wenn das Schloss freigegeben wird. Wenn also Thread-1 in den Synchronisierungsblock in c1 eintritt und einen lock1 erwirbt, kann ein weiterer Thread-2c2 erhöhen, ohne zu warten, wenn thread-1 eine Sperre freigibt.


Wichtig zu beachten:

Verwendung von this als Aktien-Monitor eine eigene Ausgabe hat, weil ein Verweis auf die Instanz von MsLunch sichtbar außerhalb von MsLunch ist. Beispielsweise.Thread-3 kann ein Schloss für: synchronized (msLunchInstance) außerhalb dieser Klasse erwerben.

+0

Danke! +1 für die Erklärung bezüglich 'this'. Ich habe nicht über diese Implikation nachgedacht - die Verwendung von 'this' könnte einige Leistungsprobleme auf sehr grobe Weise verbergen, wenn ich das richtig mache! : D – displayname