Ich habe mir den Code von Java-Concurrent-Collections angeschaut und sehe, dass sie einfach Sammlungen umschließen, indem sie am Anfang der Operation ein Schloss sperren und es am Ende aufschließen.
Was ist mit volatile
? Wenn die Back-End-Sammlung nicht flüchtig ist, können die Änderungen von anderen Threads verpasst werden, sodass die Thread-Einsparung etwas unterbrochen ist. Ich weiß, dass synchronized
dieses Problem lösen kann, aber sie verwenden nur Sperren ohne weitere Synchronisierung.
Ist das ein Problem, oder fehlt mir etwas?
Aktualisierung:
Nach einer kurzen Diskussion möchte ich die Frage ein wenig umformulieren.
Ich möchte eine Java-Sammlung in einer Umgebung mit mehreren Threads verwenden. (Zum Beispiel spreche ich gerade von PriorityBlockingQueue
)
Ich möchte sicher sein, dass die Änderungen, die ein Thread an der Sammlung vornimmt (push / pop), für andere sofort sichtbar sind.
Es ist gut, dass Java-gleichzeitige Sammlungen mich daran hindern, in Schwierigkeiten zu geraten, um den inneren Zustand der Sammlung stabil zu halten, wenn die Anzahl der Threads es aktualisiert, aber Ich möchte sicher sein, dass die Daten selbst für alle Threads sichtbar ist.
Die Frage ist: Habe ich Recht, dass Java-Concurrent-Sammlungen diese Funktion nicht standardmäßig bereitstellen? Und wenn ich das tue, welche zusätzlichen (minimalistischen) Techniken sollte ich verwenden, um die gewünschte Sichtbarkeit zu erreichen?
Danke.
Aus BlockingQueue
Javadoc:
Speicherkonsistenzeffekte: Wie bei anderen gleichzeitigen Auflistungen werden Aktionen in einem Thread vor dem Platzieren eines Objekts in einer
BlockingQueue
happen-before Aktionen nach dem Zugriff auf dieses Element oder dem Entfernen aus diesem Element ausgeführt. co_de% in einem anderen Thread.
BlockingQueue
stellt dieses Verhalten mithilfe eines PriorityBlockingQueue
bereit, das eine Implementierung von ReentrantLock
):
... stellt [s] die gleiche Speichersynchronisations-Semantik zur Verfügung wie die integrierte Monitorsperre, wie in JLS ...
Ich habe den Code von Java angeschaut gleichzeitige Sammlungen und ich sehe das Sie wickeln einfach einfache Sammlungen mit Locking am Anfang von die Operation und Entriegelung in der Ende.
Welche Quelle hast du gelesen?
Dies ist eine Überallgeneralisierung. Es hängt ganz davon ab, welche Sammlung Sie betrachten. Zum Beispiel macht CopyOnWriteArrayList
nichts von der Sortierung, sondern erstellt jedes Mal ein völlig neues Array, wenn Sie Elemente hinzufügen oder entfernen, was bedeutet, dass alle geöffneten Iterator
oder ListIterator
weiterhin mit den alten Daten laufen; Dieser Effekt ist beabsichtigt.
Was ist mit volatilen? Wenn das Back-End Sammlung ist nicht volatil die Änderungen könnte von anderen Threads übersehen werden, und so ist die Thread-Einsparung etwas gebrochen. Ich kenne das synchronisiert Lösung dieses Problems, aber sie verwenden nur sperrt ohne weiteres weiter Synchronisierung.
Die meisten gleichzeitigen Auflistungen sind vorhanden, um sicherzustellen, dass Iteratoren weiterhin mit der alten Version und nicht mit der neuen Version arbeiten, die Daten aktualisiert hat. etwas, das volatile
nicht garantieren würde. Dieses Verhalten bedeutet auch, dass die Iteratoren nicht in einem inkonsistenten Zustand verbleiben und somit verhindert wird, dass ConcurrentModificationException
ausgelöst wird.
BEARBEITEN : Nachdem die ursprüngliche Frage geklärt wurde, ist diese Antwort nicht länger relevant. Die folgende Antwort ist relevant für den Fall, dass Collections.synchronized * Methoden, um nicht-threadsichere Sammlungen threadsicher zu machen.
Wenn Sie einen Codeblock synchronisieren, der auch dazu führt, dass verschiedene Threads den (möglicherweise geänderten) Zustand synchronisieren.
[...]
Bei beiden Lösungen muss die Variable clkID
mit dem Hauptspeicher abgeglichen werden. Der Zugriff auf die Variable clkID
von der synchronisierten Methode oder dem synchronisierten Block ermöglicht nicht die gleichzeitige Ausführung dieses Codes, garantiert jedoch, dass die Variable clkID
im Hauptspeicher entsprechend aktualisiert wird. Der Hauptspeicher wird aktualisiert, wenn die Objektsperre erhalten wird, bevor der geschützte Code ausgeführt wird, und dann, wenn die Sperre aufgehoben wird, nachdem der geschützte Code ausgeführt wurde.
[...]
Quelle : Verwenden Sie beim Zugriff auf gemeinsame Variablen Synchronisiert oder Flüchtig
Hier sind die punktweisen Antworten auf Ihre Fragen. 1. Alle Java-Auflistungsdatenstrukturen im Parallelitätspaket wickeln entsprechende nicht threadsichere Auflistungsdatenstrukturen nicht ein. 2. Es gibt Möglichkeiten, Thread-Sicherheit ohne Sperren oder Synchronisation zu erreichen. Das Schreiben von lockfreien Datenstrukturen ist komplizierter und normalerweise sollten Sie für die allgemeine Entwicklung vermeiden. Wenn jedoch eine verfügbar ist, sollten Sie diese anstelle der entsprechenden Sperrversion der Datenstruktur verwenden. 3. Sperren Sie freie Datenstruktur verwenden Sie nicht Sperren, stellen Sie noch die ganze Sicherheit und Lebendigkeitseigenschaft zur Verfügung. 4. Beispiel-API ist ConcurrentSkipListMap, das ist lock-freie gleichzeitige probabilistische Karte (wahrscheinlich die komplizierteste Implementierung in Java)
Tags und Links java multithreading thread-safety concurrency collections