Java Concurrency: Gekoppelte Sperren mit gemeinsamem Zugriff

9

Ich suche nach einer Java-Implementierung der folgenden Parallelitätssemantik. Ich möchte etwas ähnliches wie ReadWriteLock , außer symmetrisch, d. H. Sowohl die Lese- als auch die Schreibseite können unter vielen Threads geteilt werden, aber Lesen schließt Schreiben aus und umgekehrt .

  1. Es gibt zwei Sperren, nennen wir sie A und B.
  2. Sperre A ist geteilt, d. h. es können mehrere Threads gleichzeitig sein. Sperre B wird ebenfalls gemeinsam genutzt. Es kann mehrere Threads geben, die ihn gleichzeitig halten.
  3. Wenn irgendein Thread Sperre A enthält, dann kann kein Thread B - Threads nehmen, die versuchen B zu blockieren, bis alle Threads, die A enthalten, A freigegeben haben.
  4. Wenn irgendein Thread Block B enthält, dann kein Thread kann A nehmen - Threads, die versuchen, A zu nehmen, werden blockiert, bis alle Threads, die B enthalten, B freigegeben haben.

Gibt es eine vorhandene Bibliotheksklasse, die dies erreicht? Im Moment habe ich die gewünschte Funktionalität mit einem ReadWriteLock angenähert, da glücklicherweise die im Zusammenhang mit Lock B durchgeführten Aufgaben etwas seltener sind. Es fühlt sich jedoch an wie ein Hack und könnte die Leistung meines Programms unter hoher Last beeinträchtigen.

    
Neil Bartlett 28.12.2016, 08:49
quelle

4 Antworten

3

Kurze Antwort:

In der Standardbibliothek gibt es nichts, was Sie brauchen.

Lange Antwort:

Um ein benutzerdefiniertes Lock einfach zu implementieren, sollten Sie eine Unterklasse erstellen oder an ein AbstractQueuedSynchronizer .

Der folgende Code ist ein Beispiel für eine nicht faire Sperre, die das implementiert Sie benötigen, einschließlich einiger (nicht anstrengenden) Test. Ich habe es LeftRightLock wegen der binären Natur Ihrer Anforderungen genannt.

Das Konzept ist ziemlich einfach:

AbstractQueuedSynchronizer macht eine Methode verfügbar, um den Status eines int mithilfe des Vergleichs und Tausches idiom ( compareAndSetState ( int expect, int update) ), können wir den exposed state verwenden, um die Anzahl der Threads zu halten, die die Sperre halten, und einen positiven Wert für den Fall setzen, dass die Right -Sperre gehalten wird, oder einen negativen Wert für case Die Left -Sperre wird gehalten.

Dann stellen wir nur die folgenden Bedingungen sicher: - Sie können Left nur sperren, wenn der Status des internen AbstractQueuedSynchronizer zero oder negativ ist - Sie können Right nur dann sperren, wenn der Status des internen AbstractQueuedSynchronizer zero oder positiv

ist

LinksRechtssperre.java

%Vor%

LinksRechtsTest.java

%Vor%     
snovelli 10.01.2017 16:18
quelle
1

Ich kenne keine Bibliothek, die das tut, was Sie wollen. Selbst wenn es eine solche Bibliothek gibt, hat sie wenig Wert, denn jedes Mal, wenn sich Ihre Anfrage ändert, hört die Bibliothek auf, Magie zu tun.

Die eigentliche Frage hier ist "Wie implementiere ich mein eigenes Schloss mit benutzerdefinierten Spezifikationen?"

Java stellt ein Tool zur Verfügung, das AbstractQueuedSynchronizer . Es verfügt über umfangreiche Dokumentation. Abgesehen von Dokumenten möchte man möglicherweise auf CountDownLatch und ReentrantLock Quellen schauen und sie als Beispiele verwenden.

Bitte beachten Sie für Ihre spezielle Anfrage den folgenden Code, aber achten Sie darauf, dass es 1) nicht fair 2) nicht getestet ist

%Vor%     
Sergey Fedorov 28.12.2016 20:49
quelle
0

Wie wäre es mit

? %Vor%

Update: Was "Fairness" (oder besser: Nicht-Hunger) betrifft, erwähnen die OP-Anforderungen das nicht. Um die Anforderungen des OP + irgendeine Form von Fairness / Nicht-Verhungern umzusetzen, sollte es explizit angegeben werden (was halten Sie für fair, wie sollte es sich verhalten, wenn Anfragen für derzeit dominante und nicht-dominante Sperren eingehen usw.). Eine der Möglichkeiten, es zu implementieren, wäre:

%Vor%

Zu verwenden wie in:

%Vor%

Die Idee von Generationen ist hier aus "Java Concurrency in Practice", Listing 14.9 , entnommen.

    
starikoff 28.12.2016 19:36
quelle
0

Nach meinem n Versuch, eine einfache faire Implementierung zu machen, glaube ich zu verstehen, warum ich keine andere Bibliothek / ein Beispiel des "gegenseitigen exklusiven Lock-Pairs" finden konnte: es erfordert eine ziemlich spezifische Benutzer-Fall. Wie bereits erwähnt, können Sie mit ReadWriteLock einen langen Weg zurücklegen und ein faires Lock-Pair ist nur sinnvoll, wenn viele Anfragen für eine Sperre in schneller Folge vorliegen (sonst könnten Sie auch eine normale Sperre verwenden).

Die folgende Implementierung ist eher ein "Genehmigungsspender": Sie ist nicht einspringend. Es kann jedoch wiedereingeführt werden (wenn nicht, ich fürchte, ich habe es versäumt, den Code einfach und lesbar zu machen), aber es erfordert einige zusätzliche Verwaltung für verschiedene Fälle (z. B. ein Thread A zweimal sperren, muss immer noch zweimal A entsperren und die entsperren -Methode muss wissen, wann keine Sperren mehr bestehen. Eine Möglichkeit, einen Deadlock-Fehler auszulösen, wenn ein Thread A sperrt und B sperren möchte, ist wahrscheinlich eine gute Idee.

Der Grundgedanke ist, dass es eine "aktive Sperre" gibt, die nur durch die Lock-Methode geändert werden kann, wenn überhaupt keine (Anfragen nach) Sperren vorhanden sind und die durch die Entsperr-Methode geändert werden kann, wenn die aktiven Sperren ausstehen erreicht Null. Der Rest besteht im Wesentlichen darin, die Anzahl der Sperranforderungen zu zählen und Threads warten zu lassen, bis die aktive Sperre geändert werden kann. Das Warten auf Threads beinhaltet das Arbeiten mit InterruptedException s und ich habe dort einen Kompromiss gemacht: Ich konnte keine gute Lösung finden, die in allen Fällen gut funktioniert (z. B. Herunterfahren der Anwendung, ein Thread, der unterbrochen wird usw.).

Ich habe nur einige grundlegende Tests durchgeführt (Test-Klasse am Ende), mehr Validierung ist erforderlich.

%Vor%

Die Testklasse (YMMV - funktioniert auf meinem System gut, kann aber aufgrund schnellerem oder langsameren Starten und Ausführen von Threads auf Ihrem System hängen bleiben):

%Vor%     
vanOekel 03.01.2017 22:54
quelle

Tags und Links