Warum Java-gleichzeitige Sammlungen wirklich Thread-sicher sind

8

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.

    
jutky 23.11.2010, 18:19
quelle

5 Antworten

11

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 ...

    
SimonJ 23.11.2010, 21:07
quelle
7

Ja, du verpasst etwas. Die ReentrantLock-Klasse bietet die gleichen Garantien wie synchronisiert. Und, ReentrantLock und synchronisiert bieten beide die gleichen Speichergarantien wie flüchtig.

    
james 23.11.2010 19:20
quelle
6
  

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.

    
Powerlord 23.11.2010 18:35
quelle
5

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

    
Neeme Praks 23.11.2010 18:22
quelle
0

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)

    
Mahesh 05.12.2010 08:31
quelle