Was macht ReentrantLock # tryLock (long, TimeUnit), wenn es versucht, die Sperre zu übernehmen?

8

Was macht die ReentrantLock # tryLock (long, TimeUnit) Implementierung, wenn sie versucht, eine Sperre zu erstellen? Angenommen, Thread A besitzt die Sperre von myLock und Thread B-Aufruf myLock.tryLock(10,SECONDS) , ist Thread B inaktiv oder wartet?

Mit anderen Worten, war der Unterschied dieser 2 Implementierungen:

1.

%Vor%

2.

%Vor%     
Chriss 06.12.2011, 10:27
quelle

5 Antworten

3

Zuallererst wartet der zweite auf weniger als 5 Millis, wenn die Sperre aufgehoben wird, weil er nicht auf das Aufwachen von sleep warten muss. Es ist also weniger dem Hungerproblem ausgesetzt.

Dann verwendet j.u.c.l package LockSupport # park-Methoden, um einen Thread anzuhalten, nicht Thread.sleep . Und wie ich es verstehe, macht es im Thread-Scheduler einen Unterschied, die park erlaubt eine niedrigere Latenz, aber nicht sicher, wie genau sleep implementiert ist.

Auch macht Ihr Code keinen Sinn, genau derselbe Effekt könnte mit lock() method erreicht werden.

    
kan 06.12.2011, 10:42
quelle
1

Es wartet auf die Sperre und der Thread schläft.

Intern wartet die Methode tryLock(long, TimeUnit) die Sperre sofort ab und wartet auf die angegebene Zeit. Wenn das Schloss vor dieser Zeit verfügbar wird, kehrt es sofort mit dem Schloss zurück. Beachten Sie, dass in diesem Fall, wenn mehrere Threads eine Sperre anfordern, der ReentrantLock nach dem Zufallsprinzip einen Thread auswählt, um den nächsten zu sperren. Dieses Verhalten kann geändert werden, indem true an den Fairness-Wert im Konstruktor new ReentrantLock(true) übergeben wird.

Im zweiten Beispiel wird nur alle fünf Millisekunden nach der Sperre gesucht. Wenn die Sperre verfügbar wird, während sie inaktiv ist, und sie einem anderen Thread zugewiesen wird, bevor sie aktiviert wird, ist dieser Thread für die Erfassung der Sperre nicht verfügbar.

Wenn Sie diesen Code mit vielen Threads verwenden, die auf die Sperre warten, beachten Sie, dass keine der von Ihnen bereitgestellten Lösungen garantiert, dass jeder Thread irgendwann die Sperre erhält. Der zweite Code kann weiterhin kurz vor Ablauf der fünf Millisekunden von einem anderen Thread abgefangen werden. Der erste Code ist zufällig, aber selbst bei gesetztem Fairness-Wert gibt jeder Thread alle fünf Millisekunden seinen Platz in der Zeile auf. Wenn dies der Fall ist, erhöhen Sie besser den Zeitüberschreitungswert. Ein guter Wert wäre etwa das Doppelte der maximalen Zeit, die Sie erwarten würden, damit jeder Thread eine Runde bekommt.

    
Erick Robertson 06.12.2011 10:44
quelle
1

Technisch gibt es keinen Unterschied in Bezug auf den Zustand des wartenden Threads. Aus dem JavaDoc:

  

Wenn die Sperre von einem anderen Thread gehalten wird, wird der aktuelle Thread deaktiviert       für die Thread-Planung und liegt ruhend [...]

Dies ist sehr ähnlich dem, was beim Schlafen passiert, aber ich denke, wir können es nicht sicher sagen, wenn wir die Implementierung nicht kennen.

Beachten Sie jetzt diesen Teil:

  

[...] ruht, bis eines von drei Dingen passiert:       Die Sperre wird vom aktuellen Thread übernommen. oder [...]

Das heißt, falls das Schloss in der Zwischenzeit frei wird, wird es es erwerben und zurückgeben. Im anderen Fall, während es schläft, hat der Thread keine Chance, das Schloss zu bekommen, auch wenn es frei ist.

Ein weiterer subtiler Unterschied, der zwischen den beiden Fällen auftreten kann, ist die Tatsache, dass das zeitgesteuerte Trylock empfindlich auf die Fairness-Politik des ReentrantLock reagiert. Das ist:

  

Wenn diese Sperre so eingerichtet wurde, dass sie eine faire Bestellrichtlinie verwendet, dann eine verfügbare Sperre       wird nicht erfasst, wenn andere Threads auf die Sperre warten.

Es ist bekannt, dass das untimed trelock nicht fair ist und es vielleicht gelingt, das Schloss zu erhalten, selbst wenn andere Threads bereits darauf warten.

    
Tudor 06.12.2011 10:42
quelle
0

Ich schätze, dass der zweite auf 5 Millisekunden warten wird, um eine Sperre zu bekommen, die sich von der ersten unterscheidet, die sofort versuchen wird, zu sperren. Thread B wird also warten, wenn er in 5 ms (innerhalb von 5 ms) gesperrt wird und keine Sperre erhält, wird false zurückgegeben. Normalerweise gibt es keinen Unterschied, wenn Sie 5ms in Ihrem Timeout haben, aber wenn Sie diese Zahl erhöhen, erhalten Sie das klare Bild.

5ms ist ein Timeout, es wird auf 5ms für eine Sperre gewartet, das heißt, wenn die Sperre nach 3ms verfügbar ist, wird sie nach 3ms mit True zurückgegeben.

    
AlexTheo 06.12.2011 10:36
quelle
0

Für eine großartige Referenz, wie Locks und andere Parallelitätsprimitive implementiert werden, siehe Shavit und Herlihy's exzellente Die Kunst der Multiprozessorprogrammierung .

    
Jed Wesley-Smith 06.12.2011 20:03
quelle