Need Fool Proof Synchronisierung von ArrayList in einer Umgebung mit mehreren Threads

8

Ich bin seit einer Woche dabei und erforsche, wie man eine ArrayList richtig synchronisiert.

Mein Hauptproblem ist kurz gesagt, ich habe eine "Master" ArrayList von Objekten. Verschiedene Threads können kommen und fügen / setzen / entfernen von dieser Liste. Ich muss sicher sein, dass wenn ein Thread durch die ArrayList iteriert, ein anderer es nicht ändert.

Nun habe ich viele Artikel über den "besten" Weg gelesen, dies zu handhaben:

  • verwende collections.synchronizedlist
  • benutze CopyOnWriteArrayList
  • verwendet synchronisierte () Blöcke in Verbindung mit collections.synchronizedlist
  • benutze Vector (viele Leute sind dagegen)

Wenn ich synchronisierte Blöcke um jede Iteration verwende, scheint das Hinzufügen / Setzen / Entfernen von Blöcken etwas von dem zu sein, was ich will, aber die Leute haben gesagt, dass es viel Overhead gibt.

Also habe ich angefangen, mit CopyOnWriteArrayList zu spielen (ich kann viel mehr lesen als schreibe für meine Master ArrayList). Das ist gut zum Lesen, aber was viele Forum-Threads nicht erwähnen, ist, dass Elemente nicht hinzugefügt, gesetzt oder aus dem Iterator selbst entfernt werden können. Zum Beispiel (eine Basisversion, aber stellen Sie es sich in einer Multithread-Umgebung vor):

%Vor%

die Zeile "litr.set (neues TestObject (" TEST "));" würde ein

werfen %Vor%

Und in der Java-Dokumentation gibt es eine spezielle Zeile, die dieses Verhalten beschreibt:

"Elementändernde Operationen an Iteratoren selbst (entfernen, setzen und hinzufügen) werden nicht unterstützt. Diese Methoden werfen UnsupportedOperationException."

Dann müssen Sie diese Liste ändern, indem Sie

verwenden %Vor%

Technisch sollte das jetzt kein Synchronisationsproblem darstellen? Wenn ein anderer Thread zur gleichen Zeit kommen würde und sagen würde, alle Elemente aus der "Liste" entfernen, würde der Iterator das nicht sehen, würde die "Liste" auf einen bestimmten Index setzen und würde eine Ausnahme wegen des Elements werfen an diesem Punkt existiert nicht mehr. Ich verstehe den Punkt von CopyOnWriteArrayList einfach nicht, wenn Sie ein Element nicht durch den Iterator selbst hinzufügen können.

Fehle ich den Punkt mit CopyOnWriteArrayList?

Umgehe ich jeden Iterator, der am Ende ein Element in einem synchronisierten Block hinzufügen / setzen / entfernen muss?

Dies muss ein häufiges Problem mit Multithreading sein. Ich hätte gedacht, dass jemand eine Klasse gemacht hätte, die das alles ohne Sorgen bewältigen konnte ...

Vielen Dank im Voraus, dass Sie sich das angesehen haben!

    
Liam 19.10.2012, 19:30
quelle

4 Antworten

3

Wie Sie selbst herausgefunden haben, ist CopyOnWriteArrayList NOT ABLE , um absolut sichere Änderungen vorzunehmen, wenn jemand die Daten verarbeitet, besonders nicht während der Iteration über die Liste. Denn: Wann immer Sie an den Daten arbeiten, gibt es keinen Kontext , um sicherzustellen, dass Ihr vollständiger Anweisungsblock, der auf die Liste zugreift, ausgeführt wird, bevor jemand anders die Listendaten geändert hat.

Daher müssen Sie MUST für alle Ihre Zugriffsoperationen (auch für das Lesen!) einen Kontext (wie die Synchronisation) haben, der Ihren gesamten Datenzugriffsblock ausführt. Zum Beispiel:

%Vor%

Oder für Iteratoren:

%Vor%

Aber jetzt kommt das große Problem mit dieser Art von Synchronisation: Es ist langsam und erlaubt keinen Lesezugriff Daher wäre es nützlich, einen eigenen Kontext für den Datenzugriff zu erstellen. Ich werde die ReentrantReadWriteLock verwenden, um mehrere Lesezugriffe zu ermöglichen und die Leistung zu verbessern.
Ich bin sehr an diesem Thema interessiert und werde einen solchen Kontext für die ArrayList erstellen und es hier anhängen, nachdem ich es abgeschlossen habe.

20.10.2012 | 18:30 - BEARBEITEN: Ich habe einen eigenen Zugriffskontext mit dem ReentrantReadWriteLock für eine sichere ArrayList erstellt.
Zuerst werde ich die gesamte SecureArrayList-Klasse einfügen (die meisten der ersten Operationen überschreiben und schützen), dann füge ich meine Tester-Klasse mit der Erklärung der Nutzung.
Ich habe gerade den Zugang mit einem Thread getestet, nicht mit vielen gleichzeitig, aber ich bin mir ziemlich sicher, dass es funktioniert! Wenn nicht, bitte sag es mir.

SecureArrayList:

%Vor%

SecureArrayList_Test:

%Vor%

Bearbeiten: Ich habe ein paar Testfälle hinzugefügt, um die Funktionalität in Threads zu demonstrieren. Die obige Klasse funktioniert perfekt und ich benutze sie jetzt in meinem Hauptprojekt (Liam):

%Vor%     
Thomas 19.10.2012, 22:26
quelle
1

Ein anderer Ansatz besteht darin, den gesamten Zugriff auf die Liste zu schützen, jedoch mit einem ReadWriteLock anstelle von synchronisierten Blöcken.

Dies ermöglicht das gleichzeitige Lesen auf sichere Weise und könnte die Leistung in einem Szenario mit vielen Lesevorgängen und wenigen Schreibvorgängen erheblich verbessern.

    
the_ien 19.10.2012 19:45
quelle
1

Verwenden Sie CopyOnWriteArrayList, und synchronisieren Sie nur bei Schreibvorgängen

%Vor%

Daher werden sich keine zwei Schreibsitzungen überlappen.

Lesevorgänge erfordern keine Sperre. Eine Lesesitzung kann jedoch eine sich ändernde Liste anzeigen. Wenn eine Lesesitzung einen Snapshot der Liste anzeigen soll, verwenden Sie entweder iterator() , oder erstellen Sie einen Snapshot nach toArray() .

Es ist wahrscheinlich sogar besser, wenn Sie die Kopie selbst schreiben

%Vor%     
irreputable 19.10.2012 20:14
quelle
0

Wenn Sie während einer Iteration ändern, müssen Sie Option 3 verwenden. Keiner der anderen wird tatsächlich tun, was Sie wollen.

Genauer gesagt: Wenn Sie angeben, was Sie tun möchten, haben Sie die gesamte Liste für die Länge der Iteration zu sperren, da Sie sie möglicherweise in der Mitte ändern, wodurch andere Iteratoren beschädigt werden auf der Liste zur gleichen Zeit. Das bedeutet Option 3, da die Sprache Java nicht nur einen "synchronisierten Iterator" haben kann - der Iterator selbst kann nur einzelne Aufrufe von hasNext() oder next() synchronisieren, aber er kann nicht über die gesamte Länge des Iteration.

    
Louis Wasserman 19.10.2012 19:37
quelle

Tags und Links