2015-08-27 4 views
5

Ich lese in einem Buch, das in ConcurrentHashmap gelesen wird, garantiert nicht den zuletzt aktualisierten Zustand und es kann manchmal den engeren Wert geben. Ist das richtig?Ist der Lesevorgang in ConcurrentHashMap hinsichtlich des Rückgabewerts zuverlässig?

Ich habe seine javadocs und viele Blogs lesen, die sonst scheint zu sagen (das heißt, es ist genau).

Welches ist wahr?

+0

Wie planen Sie, die Daten zu lesen? –

+0

mit einfachen get() –

+1

Dann sollten Sie sich keine Sorgen machen, wird es den genauesten Wert zurückgeben. –

Antwort

0

Das ist die Natur der Nebenläufigkeit. Jede gleichzeitige Sammlung kann Ihnen den alten Wert in einem Feld geben, wenn eine momentan ausstehende Schreiboperation nicht sicher beendet wird. Das ist in allen Fällen, was Sie zu erwarten haben. Die Sammlungen, die für den gemeinsamen Zugriff erstellt werden, geben Ihnen keine beschädigten Werte oder brechen ab, wenn Sie auf sie aus mehreren Threads zugreifen, aber sie können Ihnen alte Werte geben, wenn das Schreiben nicht erfolgt.

+1

Wenn der Wert nicht überschrieben wird, dann ist es kein alter Wert, es ist der aktuelle ... Sicherlich gibt es Ihnen nicht den zukünftigen Wert, der normal ist – Dici

+0

Ja. Aber mit Nebenläufigkeit ist es möglich, einen Wert zu lesen * während * es geschrieben wird. Die "normalen" Sammlungen machen etwas undefiniertes, wenn das passiert. Die gleichzeitigen Sammlungen geben Ihnen den alten Wert oder Block, bis das Schreiben abgeschlossen ist. – Nitram

+0

Sie können nicht 'Collections.SynchronizedCollection' dafür betrachten. Dies ist ein einfacher Low-Performance-Wrapper für eine normale Sammlung. Sehen Sie sich die ConcurrentHashMap-Implementierung an. – Nitram

0

Von ConcurrentHashMap javadoc:

Retrieval-Operationen (einschließlich get) in der Regel nicht blockieren, so kann mit Update-Operationen überlappt (Put einschließlich und entfernen). Retrievals spiegeln die Ergebnisse der zuletzt abgeschlossenen Aktualisierungsoperationen wider, die an ihrem Beginn anhalten. Für Aggregatoperationen wie putAll und clear können gleichzeitige Abrufvorgänge das Einfügen oder Entfernen von nur einigen Einträgen widerspiegeln. In ähnlicher Weise geben Iteratoren und Enumerationen Elemente zurück, die den Zustand der Hash-Tabelle zu irgendeinem Zeitpunkt bei oder seit der Erzeugung des Iterators/der Enumeration widerspiegeln. Sie werfen ConcurrentModificationException nicht aus. Iteratoren können jedoch nur von jeweils einem Thread verwendet werden.

Ein Punkt hervorzuheben ist, dass ein Iterator wird nicht Änderungen widerspiegeln, die vorgenommen werden, nachdem die Iterator erstellt wird. Wenn Sie also über die Werte der Map iterieren müssen, während andere Threads zur Map hinzugefügt werden und Sie sich um den aktuellsten Status der Map kümmern, ist die Verwendung einer Map möglicherweise nicht die von Ihnen benötigte Map.

+1

Danke für die Reinigung. Es sieht viel besser aus! – bombe

+0

'Collections.synchronizedMap' scheint alle ** Zugriffe zu synchronisieren. Warum diese Designauswahl in 'ConcurrentHashMap'? – Dici

1

Intuitiv ein ConcurrentHashMap sollte wie eine Reihe von flüchtigen Variablen verhalten; Kartenschlüssel sind die Variablenadressen. get(key) und put(key, value) sollten sich wie flüchtiges Lesen und Schreiben verhalten.

Das ist nicht explizit in dem Dokument angegeben. Ich bin jedoch der festen Überzeugung, dass dies der Fall ist. Andernfalls wird es viele unerwartete, überraschende Verhaltensweisen geben, die die Anwendungslogik unterminieren. Ich glaube nicht, dass Doug Lea uns das antun würde. Um sicher zu sein, fragen Sie ihn bitte auf concurrency-interest Mailing-Liste.

Angenommen es die flüchtige Semantik nicht gehorcht, können wir auf Basis von Java-Speichermodell Reason -

Alle flüchtig liest und schreibt einen einzigen Gesamtauftrag bilden. Dies kann als eine Pseudo-Zeitlinie betrachtet werden, bei der Lese-/Schreibvorgänge Punkte sind.

Ein flüchtiges Lesen sieht die sofortige volatil vorhergehenden Schreib, und sieht nur den Schreib. "Preceding" entspricht hier der Pseudo-Zeitlinie.

Die Pseudozeitlinie kann von „real“ Zeitlinie abweichen. Theoretisch kann ein flüchtiger Schreibvorgang jedoch nicht unendlich auf die Pseudo-Zeitlinie verschoben werden. Und in der Praxis sind zwei Zeitlinien ziemlich nah.

Deshalb können wir ziemlich sicher sein, dass ein flüchtiger Schreib sichtbar „sehr schnell“ werden sollte liest.

+0

... 'volatile' Variablen ... Eigentlich ist es im' ConcurrentHashMap'-API-Vertrag angegeben, aber nicht in diesen Worten. Der Javadoc sagt, "... eine Aktualisierungsoperation für einen gegebenen Schlüssel trägt eine _happens-before_-Beziehung mit jedem (Nicht-Null-) Abruf für diesen Schlüssel." Das ist im Grunde das gleiche, wie "flüchtig" in der JLS beschrieben wird: Eine Aktualisierung auf ein "flüchtiges" Feld richtet _happens-before_ mit jedem nachfolgenden Lesen desselben Feldes ein. –

+0

@jameslarge - ja, aber das ist nur ein Teil der volatilen Semantik. Wir brauchen auch "Synchronisationsreihenfolge" und [Konsistenz der Synchronisationsreihenfolge] (http://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4.7) – ZhongYu

+0

vielleicht ist eine bessere Frage, sind "ConcurrentHashMap" Operationen * sequentiell konsistent ". Ich denke, es muss sein, oder zumindest Menschen, die es für selbstverständlich halten. – ZhongYu

Verwandte Themen