Kürzlich las ich einige Beispiele aus dem Kapitel 8 der Art der Multiprozessor-Programmierung , über " Monitore und Blockierungssynchronisation ", die das signalAll()
eines Condition
-Objekts verwenden, ohne dass die mit diesem Condition
verknüpfte Sperre übernommen wird.
Überraschenderweise fand ich keine Korrektur für diese Beispiele in den Buch-Errata . Außerdem schlagen sie eine Korrektur für das Beispiel in Abbildung 8.12 von FifoReadWriteLock
vor, aber sie verwenden weiterhin signalAll()
, ohne dass die Sperre gehalten wird. Das hat mich gestört und ich habe versucht, andere Überlegungen zu diesen Beispielen anzustellen, um die Gründe zu verstehen, warum diese Java-Beispiele auf diese Weise geschrieben wurden.
Zum Beispiel die Antwort auf die Frage "Wie funktioniert ein Read-Write-Mutex / Lock? "zeigt das gleiche Beispiel für die Implementierung von FifoReadWriteLock
, das writeUnlock()
als implementiert:
Über das Fehlen der Lock-Erfassung können Sie zwei verschiedene Gründe lesen:
Es ist schwierig, das erste Argument zu akzeptieren, da das Buch Beispiele in Java verwendet und ausdrücklich sagt:
Das Buch verwendet die Java-Programmiersprache.
Über den zweiten Punkt weiß ich, dass die Java-API in java.util.concurrent.locks.Condition
für signal()
Methode:
Eine Implementierung kann (und normalerweise) erfordert, dass der aktuelle Thread die mit diesem
Condition
verknüpfte Sperre bei Aufruf dieser Methode enthält.
Wenn " eine Implementierung nur " ist, bedeutet dies, dass dies NICHT zwingend erforderlich ist. Nach meinem besten Wissen finde ich keine Implementierung, die diese Anforderung NICHT erfüllt. Also würde ich gerne wissen, welche Implementierungen von Java Condition
keinen aktuellen Thread benötigen, um die Sperre zu halten?
Mir ist keine Condition
-Implementierung im JDK bekannt, die Warten oder Signalisieren erlaubt, ohne gleichzeitig den Monitor zu besitzen.
Praktisch alle java.util.concurrent
-Klassen verlassen sich auf AbstractQueuedSynchronizer
, was den gleichen Vertrag wie die eingebauten Überwachungsmethoden wait()
/ notify()
/ notifyAll()
für die von ihr bereitgestellten Bedingungsvariablen festlegt, dh Besitz erfordert die interne Sperre, um den Aufruf von await()
/ signal()
/ signalAll()
.
Wenn Sie ein einfaches Beispiel mit dem vorgeschlagenen FifoReadWriteLock
versuchen, werden Sie feststellen, dass es eine große Menge von IllegalMonitorStateExceptions
mit seiner Methode writeUnlock()
ausgibt. Diese Ausnahmen verschwinden, wenn Sie den Lock-try-finally-Ansatz von den anderen Methoden anwenden.
Während der Besitz des Monitors in der Tat nicht unbedingt erforderlich ist, zu warten oder zu signalisieren, ist es oft der bevorzugte Ansatz, da er Sie vor raschen Zustandslesungen bewahrt, sollte er nicht zu kostspielig sein wie die Übergabe zwischen den internen Wartezeiten Derselbe Monitor kann immer noch ziemlich effizient ausgeführt werden, und weil Sie ihn meistens sowohl für die Signalisierung als auch für die Planung benötigen, anstatt nur zu signalisieren.