Ich versuche zu verstehen, was die Sperre in der Parallelität so wichtig macht, wenn man sie verwenden kann synchronized (this)
. Im folgenden Dummy-Code kann ich Folgendes tun:
- synchronisierte die gesamte Methode oder synchronisierte den gefährdeten Bereich (
synchronized(this){...}
) - ODER sperren Sie den anfälligen Codebereich mit einem ReentrantLock.
Code:
private final ReentrantLock lock = new ReentrantLock();
private static List<Integer> ints;
public Integer getResult(String name) {
.
.
.
lock.lock();
try {
if (ints.size()==3) {
ints=null;
return -9;
}
for (int x=0; x<ints.size(); x++) {
System.out.println("["+name+"] "+x+"/"+ints.size()+". values >>>>"+ints.get(x));
}
} finally {
lock.unlock();
}
return random;
}
synchronized(this){synchronized(this){//some code}}
wird also keine Deadlock verursachen. Für die intrinsische Sperre, wenn sie einen Monitor für eine Ressource erhalten und ihn erneut benötigen, können sie ihn ohne Dead Lock erhalten.Antworten:
Ein ReentrantLock ist im Gegensatz zu Konstrukten unstrukturiert
synchronized
- dh Sie müssen keine Blockstruktur zum Sperren verwenden und können sogar eine Methode zwischen Methoden sperren. Ein Beispiel:Ein solcher Fluss kann nicht über einen einzelnen Monitor in einem
synchronized
Konstrukt dargestellt werden.Abgesehen davon
ReentrantLock
unterstützt Lock Poll Polling und unterbrechbare Lock Waits, die Timeout unterstützen .ReentrantLock
Unterstützt auch konfigurierbare Fairness- Richtlinien , die eine flexiblere Thread-Planung ermöglichen.ReentrantLock
kann auch skalierbarer sein und bei höheren Konflikten eine viel bessere Leistung erbringen. Mehr dazu lesen Sie hier .Diese Behauptung wurde jedoch bestritten; siehe folgenden Kommentar:
Wann sollten Sie
ReentrantLock
s verwenden? Laut diesem DeveloperWorks-Artikel ...quelle
ReentrantLockPseudoRandom
Code im Lycog-Link verwendet brandneue, unkontrollierte Sperren für jeden Aufruf vonsetSeed
undnext
ReentrantReadWriteLock
ist ein spezialisiertes Schloss währendsynchronized(this)
es sich um ein Allzweckschloss handelt. Sie sind ähnlich, aber nicht ganz gleich.Sie haben Recht damit, dass Sie
synchronized(this)
stattdessen verwenden könnten,ReentrantReadWriteLock
aber das Gegenteil ist nicht immer der Fall.Wenn Sie besser verstehen möchten, was das
ReentrantReadWriteLock
Besondere ausmacht, lesen Sie einige Informationen zur Synchronisierung von Produzenten und Verbrauchern.Im Allgemeinen können Sie sich daran erinnern, dass die Synchronisierung mit ganzen Methoden und die allgemeine Synchronisierung (unter Verwendung des
synchronized
Schlüsselworts) in den meisten Anwendungen verwendet werden können, ohne zu viel über die Semantik der Synchronisierung nachzudenken. Wenn Sie jedoch die Leistung aus Ihrem Code herausholen müssen, müssen Sie dies möglicherweise tun Erforschen Sie andere feinkörnigere oder speziellere Synchronisationsmechanismen.Übrigens kann die Verwendung
synchronized(this)
- und im Allgemeinen das Sperren mithilfe einer öffentlichen Klasseninstanz - problematisch sein, da dadurch Ihr Code für potenzielle Deadlocks geöffnet wird, da jemand anderes, der nicht wissentlich versucht, an einer anderen Stelle im Programm gegen Ihr Objekt zu sperren.quelle
public class MyLock { private final Object protectedLongLockingMonitor = new Object(); private long protectedLong = 0L; public void incrementProtectedLong() { synchronized(protectedLongLockingMonitor) { protectedLong++; } } }
Von der Oracle-Dokumentationsseite über ReentrantLock :
Ein ReentrantLock gehört dem Thread, der zuletzt erfolgreich gesperrt , aber noch nicht entsperrt wurde. Ein Thread, der die Sperre aufruft, kehrt zurück und erhält die Sperre erfolgreich, wenn die Sperre keinem anderen Thread gehört. Die Methode wird sofort zurückgegeben, wenn der aktuelle Thread die Sperre bereits besitzt.
Der Konstruktor für diese Klasse akzeptiert einen optionalen Fairness- Parameter. Wenn true festgelegt ist, wird durch Sperren der Zugriff auf den am längsten wartenden Thread bevorzugt . Andernfalls garantiert dieses Schloss keine bestimmte Zugriffsreihenfolge.
ReentrantLock-Hauptfunktionen gemäß diesem Artikel
Mit ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock können Sie die Kontrolle über das granulare Sperren bei Lese- und Schreibvorgängen weiter erlangen.
Schauen Sie sich diesen Artikel von Benjamen über die Verwendung verschiedener Arten von ReentrantLocks an
quelle
Sie können wiedereintretende Sperren mit einer Fairness-Richtlinie oder einem Timeout verwenden, um einen Thread-Mangel zu vermeiden. Sie können eine Thread-Fairness-Richtlinie anwenden. Dadurch wird vermieden, dass ein Thread ewig darauf wartet, auf Ihre Ressourcen zuzugreifen.
Die "Fairness Policy" wählt den nächsten ausführbaren Thread aus, der ausgeführt werden soll. Es basiert auf der Priorität, der Zeit seit dem letzten Lauf, bla bla
Außerdem kann Synchronize auf unbestimmte Zeit blockieren, wenn es dem Block nicht entkommen kann. Beim Wiedereintritt kann eine Zeitüberschreitung eingestellt werden.
quelle
Synchronisierte Sperren bieten keinen Mechanismus für Warteschlangen, in dem nach der Ausführung eines Threads ein parallel laufender Thread die Sperre erhalten kann. Aufgrund dessen erhält der Thread, der sich im System befindet und über einen längeren Zeitraum ausgeführt wird, nie die Chance, auf die gemeinsam genutzte Ressource zuzugreifen, was zu Hunger führt.
Wiedereintrittssperren sind sehr flexibel und haben eine Fairness-Richtlinie, nach der wir sicherstellen können, dass der länger wartende Thread die Chance erhält, auf die gemeinsam genutzte Ressource zuzugreifen, wenn ein Thread länger wartet und nach Abschluss des aktuell ausgeführten Threads abnimmt den Durchsatz des Systems und macht es zeitaufwändiger.
quelle
Nehmen wir an, dieser Code wird in einem Thread ausgeführt:
Da der Thread die Sperre besitzt, können mehrere Aufrufe gesperrt werden (), sodass die Sperre erneut aktiviert wird. Dies kann mit einem Referenzzähler erreicht werden, sodass keine erneute Sperre erforderlich ist.
quelle
Eine Sache, die Sie beachten sollten, ist:
Der Name ' ReentrantLock ' gibt eine falsche Meldung über andere Sperrmechanismen aus, dass sie nicht wieder eintreten. Das ist nicht wahr. Die über 'synchronisiert' erworbene Sperre ist auch in Java wieder verfügbar.
Der Hauptunterschied besteht darin, dass 'synchronisiert' eine intrinsische Sperre verwendet (eine, die jedes Objekt hat), während die Sperr-API dies nicht tut.
quelle
Ich denke, die wait / notify / notifyAll-Methoden gehören nicht zur Object-Klasse, da sie alle Objekte mit Methoden verschmutzen, die selten verwendet werden. Sie sind in einer speziellen Lock-Klasse viel sinnvoller. Unter diesem Gesichtspunkt ist es vielleicht besser, ein Tool zu verwenden, das explizit für den jeweiligen Job entwickelt wurde - z. B. ReentrantLock.
quelle