2009-07-09 11 views
11

Ein bisschen Hilfe bitte, bedenken Sie den Code unten.Wiedereintrittssperre

public class Widget { 
    public synchronized void doSomething() { 
     ... 
    } 
} 

public class LoggingWidget extends Widget { 
    public synchronized void doSomething() { 
     System.out.println(toString() + ": calling doSomething"); 
     super.doSomething(); 
    } 
} 

ich gelesen, dass wenn doSomething() in LoggingWidget aufgerufen wird, wird die JVM versuchen, eine Sperre auf LoggingWidget und dann auf Widget zu erwerben.

Ich bin neugierig, den Grund zu wissen. Liegt es daran, dass die JVM weiß, dass doSomething() einen Aufruf an super.doSomething() hat oder weil das Aufrufen einer Unterklassenmethode immer auch eine Sperre für die Oberklasse erhält.

Prost

+0

Sie sollten einen Verweis auf, wo Sie dies lesen, weil es nicht wahr ist :-) –

+0

Danke in der Tat für Ihre Hilfe. Ich habe die Erklärung der Wiedereintrittssperre falsch verstanden.Nachdem ich Ihre Erklärung gelesen hatte, ging ich zurück zur Quelle (ein Auszug aus dem Buch Concurrency in der Praxis) und es macht jetzt Sinn. – CaptainHastings

Antwort

9

Sie irren - die Schlösser an der Instanz Ebene erhalten werden. Es gibt nur eine Sperre in Ihrem Beispiel, weil es nur eine Instanz erstellt, wenn Sie sagen:

Widget w = new LoggingWidget 

Sie Schlösser sehen können (auch bekannt als Monitore, mutexes oder Semaphore) individuell zu sein " angebracht "an jede Objektinstanz in der JVM.

Wenn Sie eine andere synchronized Methode auf die LoggingWidget Unterklasse hätten, würden Sie dies als wahr erkennen. Es wäre nicht möglich, diese (neue) Methode und die Methode doSomething gleichzeitig [mit verschiedenen Threads auf demselben Objekt] aufzurufen.

Dies gilt auch für eine weitere synchronized-Methode für die Oberklasse (d. H. Sie wird in keiner Weise durch Methoden außer Kraft gesetzt).

1

Es gibt nur eine Instanz, um die Sperre zu aktivieren, die Instanz LoggingWidget, es gibt nie eine tatsächliche Instanz von Widget.

Die Sperre wird erhalten, wenn Sie LoggingWidget.doSomething() aufrufen und wie Sie bereits die Sperre haben, wenn Sie super.doSomething() aufrufen, wird diese Methode wie normal ausgeführt.

+0

Danke Nick, macht Sinn. – CaptainHastings

5
public synchronized void doSomething() { 
    System.out.println(toString() + ": calling doSomething"); 
    super.doSomething(); 
} 

ist die gleiche wie:

public void doSomething() { 
    synchronized (this) { 
     System.out.println(toString() + ": calling doSomething"); 
     super.doSomething(); 
    } 
} 

Sie auf der Instanz sperren, nicht die Klasse. Wenn also super.doSomething() aufgerufen wird, ist diese Instanz bereits gesperrt.

+0

Danke, wie das Lied geht, kann ich jetzt klar sehen ... – CaptainHastings

0

Reentrancy funktioniert, indem zuerst das Schloss erworben wird. Wenn ein Thread die Sperre erwirbt, ist dies im jvm bekannt. Beim Eingeben eines Codeblocks, der mit dem Thread synchronisiert wird, der gerade eine Sperre hält, dürfen sie ohne erneute Erfassung der Sperre fortfahren. Der jvm erhöht dann bei jeder Wiedereintrittsaktion einen Zähler und nimmt weiter ab, wenn er diesen Block verlässt, bis der Zählerstand Null ist. Wenn der Zählerstand Null ist, wird die Sperre aufgehoben.

0

B.Goetz - "JJava Parallelität in der Praxis" wenn intrinsische Sperren nicht reentrant sind, würde der Aufruf von super.doSomething nie die Sperre erhalten, weil sie als bereits gehalten betrachtet würde und der Thread dauerhaft warten würde für ein Schloss kann es nie erwerben. Reentrancy rettet uns in solchen Situationen vor einer Pattsituation.