java.util.concurrent
Die API stellt eine Klasse namens as bereit Lock
, die das Steuerelement grundsätzlich serialisiert, um auf die kritische Ressource zuzugreifen. Es gibt Methoden wie park()
und unpark()
.
Wir können ähnliche Dinge tun, wenn wir synchronized
Schlüsselwörter wait()
und notify() notifyAll()
Methoden verwenden können.
Ich frage mich, welches davon in der Praxis besser ist und warum?
Antworten:
Wenn Sie einfach ein Objekt sperren, würde ich es vorziehen, es zu verwenden
synchronized
Beispiel:
Sie müssen explizit
try{} finally{}
überall tun .Während mit synchronisiert, ist es super klar und unmöglich, falsch zu liegen:
Das heißt,
Lock
s kann für kompliziertere Dinge nützlicher sein, bei denen Sie nicht auf so saubere Weise erwerben und freigeben können. Ich würde es ehrlich gesagt vorziehen, BareLock
s überhaupt nicht zu verwenden und mich einfach für eine ausgefeiltere Parallelitätskontrolle wie aCyclicBarrier
oder a zu entscheidenLinkedBlockingQueue
, wenn sie Ihren Anforderungen entspricht.Ich hatte noch nie einen Grund zu benutzen
wait()
odernotify()
aber es kann einige gute geben.quelle
std::lock_guard
Ich habe festgestellt, dass
Lock
undCondition
(und andere neueconcurrent
Klassen) nur mehr Werkzeuge für die Toolbox sind. Ich konnte fast alles, was ich brauchte, mit meinem alten Klauenhammer (demsynchronized
Schlüsselwort) tun , aber es war in manchen Situationen umständlich, ihn zu verwenden. Einige dieser unangenehmen Situationen wurden viel einfacher, als ich meinem Werkzeugkasten weitere Werkzeuge hinzufügte: einen Gummihammer, einen Kugelhammer, einen Stemmeisen und einige Nagelstempel. jedoch , mein alter Klauenhammer sieht immer noch seinen Anteil an der Nutzung.Ich denke nicht, dass einer wirklich "besser" ist als der andere, sondern dass jeder besser für verschiedene Probleme geeignet ist. Kurz gesagt, das einfache Modell und die bereichsorientierte Natur von
synchronized
helfen mir, mich vor Fehlern in meinem Code zu schützen, aber dieselben Vorteile sind manchmal Hindernisse in komplexeren Szenarien. Es sind diese komplexeren Szenarien, für deren Behebung das gleichzeitige Paket erstellt wurde. Die Verwendung dieser übergeordneten Konstrukte erfordert jedoch eine explizitere und sorgfältigere Verwaltung des Codes.===
Ich denke, dass JavaDoc die Unterscheidung zwischen
Lock
und gut beschreibtsynchronized
(der Schwerpunkt liegt bei mir):quelle
Sie können alles , was der Dienstprogramme in erreichen java.util.concurrent wie bei dem Low-Level - Primitive tun
synchronized
,volatile
oder Warte / benachrichtigenParallelität ist jedoch schwierig, und die meisten Leute verstehen zumindest einige Teile falsch, wodurch ihr Code entweder falsch oder ineffizient (oder beides) wird.
Die gleichzeitige API bietet einen übergeordneten Ansatz, der einfacher (und damit sicherer) zu verwenden ist. Kurz gesagt, Sie sollten nicht
synchronized, volatile, wait, notify
mehr direkt verwenden müssen.Die Lock - Klasse selbst auf der unteren Ebene Seite dieser Toolbox ist, können Sie nicht einmal , dass entweder direkt verwenden müssen (Sie verwenden können ,
Queues
und Semaphore und Sachen, etc, die meiste Zeit).quelle
java.util.concurrent
[im Allgemeinen] einfacher ist als die Sprachfunktionen (synchronized
usw.). Wenn Sie verwendenjava.util.concurrent
, müssen Sie es sich zur Gewohnheit machen,lock.lock(); try { ... } finally { lock.unlock() }
vor dem Schreiben von Code zu vervollständigen , während Sie mit asynchronized
von Anfang an in Ordnung sind. Allein auf dieser Basis würde ich sagen,synchronized
ist einfacher (vorausgesetzt, Sie wollen sein Verhalten) alsjava.util.concurrent.locks.Lock
. Par 4Es gibt 4 Hauptfaktoren, warum Sie
synchronized
oder verwenden möchtenjava.util.concurrent.Lock
.Hinweis: Synchronisiertes Sperren ist das, was ich meine, wenn ich intrinsisches Sperren sage.
Als Java 5 mit ReentrantLocks herauskam, zeigten sie einen beachtlichen Durchsatzunterschied gegenüber dem intrinsischen Sperren. Wenn Sie nach einem schnelleren Verriegelungsmechanismus suchen und 1.5 ausführen, sollten Sie jucReentrantLock in Betracht ziehen. Die intrinsische Sperrung von Java 6 ist jetzt vergleichbar.
jucLock verfügt über verschiedene Sperrmechanismen. Sperre unterbrechbar - Versuch zu sperren, bis der Sperrfaden unterbrochen ist; zeitgesteuerte Sperre - Versuchen Sie, für eine bestimmte Zeit zu sperren und aufzugeben, wenn Sie keinen Erfolg haben. tryLock - Versuch zu sperren, wenn ein anderer Thread die Sperre hält, gib auf. Dies alles ist bis auf das einfache Schloss enthalten. Die intrinsische Verriegelung bietet nur eine einfache Verriegelung
quelle
Ich möchte noch einige Dinge zur Antwort von Bert F hinzufügen .
Locks
unterstützen verschiedene Methoden zur feinkörnigeren Sperrsteuerung, die aussagekräftiger sind als implizite Monitore (synchronized
Sperren)Vorteile der Sperre über Synchronisation von Dokumentation Seite
Die Verwendung synchronisierter Methoden oder Anweisungen ermöglicht den Zugriff auf die implizite Monitorsperre, die jedem Objekt zugeordnet ist, erzwingt jedoch die blockstrukturierte Erfassung und Freigabe aller Sperren
Sperrenimplementierungen bieten zusätzliche Funktionen gegenüber der Verwendung synchronisierter Methoden und Anweisungen, indem sie einen nicht blockierenden Versuch zum Erfassen von a
lock (tryLock())
, einen Versuch zum Erfassen der Sperre, die unterbrochen werden kann (lockInterruptibly()
und einen Versuch zum Erfassen der Sperre, die dies kann) bereitstellentimeout (tryLock(long, TimeUnit))
.Eine Lock-Klasse kann auch ein Verhalten und eine Semantik bereitstellen, die sich erheblich von denen der impliziten Monitorsperre unterscheiden, z. B. garantierte Reihenfolge, nicht wiedereintretende Verwendung oder Deadlock-Erkennung
ReentrantLock : Ermöglicht nach meinem Verständnis in einfachen Worten,
ReentrantLock
dass ein Objekt von einem kritischen Abschnitt in einen anderen kritischen Abschnitt zurückkehrt. Da Sie bereits über eine Sperre verfügen, um einen kritischen Abschnitt einzugeben, können Sie mithilfe der aktuellen Sperre einen anderen kritischen Abschnitt für dasselbe Objekt erstellen.ReentrantLock
Hauptmerkmale gemäß diesem ArtikelSie können
ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock
damit die Kontrolle über das granulare Sperren bei Lese- und Schreibvorgängen weiter erlangen.Abgesehen von diesen drei ReentrantLocks bietet Java 8 eine weitere Sperre
StampedLock:
Mit diesen Stempeln können Sie entweder eine Sperre aufheben oder prüfen, ob die Sperre noch gültig ist. Zusätzlich gestempelte Sperren unterstützen einen anderen Sperrmodus, der als optimistisches Sperren bezeichnet wird.
Schauen Sie sich diesen Artikel über die Verwendung verschiedener Arten von
ReentrantLock
undStampedLock
Schlössern an.quelle
Der Hauptunterschied ist die Fairness. Mit anderen Worten, werden Anfragen per FIFO bearbeitet oder kann es zu einem Barging kommen? Die Synchronisation auf Methodenebene gewährleistet eine faire oder FIFO-Zuweisung der Sperre. Verwenden von
oder
garantiert keine Fairness.
Wenn Sie viele Konflikte um die Sperre haben, können Sie leicht auf Barging stoßen, wenn neuere Anforderungen die Sperre erhalten und ältere Anforderungen stecken bleiben. Ich habe Fälle gesehen, in denen 200 Threads in kurzer Zeit für eine Sperre eintreffen und der zweite, der ankommt, zuletzt verarbeitet wurde. Dies ist für einige Anwendungen in Ordnung, für andere jedoch tödlich.
Eine ausführliche Beschreibung dieses Themas finden Sie in Brian Goetz 'Buch "Java Concurrency In Practice", Abschnitt 13.3.
quelle
Brian Goetz 'Buch "Java Concurrency In Practice", Abschnitt 13.3: "... Wie das Standard-ReentrantLock bietet das intrinsische Sperren keine deterministischen Fairness-Garantien, aber die statistischen Fairness-Garantien der meisten Locking-Implementierungen sind für fast alle Situationen gut genug ..."
quelle
Lock erleichtert Programmierern das Leben. Hier sind einige Situationen, die mit Lock einfacher erreicht werden können.
Währenddessen werden die Sperre und die Bedingungen auf dem synchronisierten aufgebaut. Damit können Sie sicher das gleiche Ziel erreichen. Dies könnte jedoch Ihr Leben erschweren und Sie von der Lösung des eigentlichen Problems abweichen.
quelle
Hauptunterschied zwischen Sperre und Synchronisation:
quelle
Das Sperren und Synchronisieren des Blocks dient demselben Zweck, hängt jedoch von der Verwendung ab. Betrachten Sie den folgenden Teil
Wenn im obigen Fall ein Thread in den Synchronisationsblock eintritt, wird auch der andere Block gesperrt. Wenn mehrere solcher Synchronisationsblöcke für dasselbe Objekt vorhanden sind, sind alle Blöcke gesperrt. In solchen Situationen kann java.util.concurrent.Lock verwendet werden, um ein unerwünschtes Sperren von Blöcken zu verhindern
quelle