Ich habe eine Map, die von mehreren Threads gleichzeitig geändert werden soll.
Es scheint drei verschiedene synchronisierte Map-Implementierungen in der Java-API zu geben:
Hashtable
Collections.synchronizedMap(Map)
ConcurrentHashMap
Soweit ich weiß, Hashtable
handelt es sich um eine alte Implementierung (Erweiterung der veralteten Dictionary
Klasse), die später an die Map
Schnittstelle angepasst wurde . Während es ist synchronisiert, so scheint es ernst zu haben Skalierbarkeitsprobleme und wird für neue Projekte abgeraten.
Aber was ist mit den anderen beiden? Was sind die Unterschiede zwischen von Collections.synchronizedMap(Map)
und ConcurrentHashMap
s zurückgegebenen Karten ? Welches passt zu welcher Situation?
java
dictionary
concurrency
Henning
quelle
quelle
ConcurrentSkipListMap
als weitere thread-sichereMap
Implementierung eingeführt. Entwickelt, um unter Last mit dem Skip List- Algorithmus sehr gleichzeitig zu sein .Antworten:
Verwenden Sie für Ihre Bedürfnisse
ConcurrentHashMap
. Es ermöglicht die gleichzeitige Änderung der Map von mehreren Threads aus, ohne dass diese blockiert werden müssen.Collections.synchronizedMap(map)
Erstellt eine blockierende Map, die die Leistung beeinträchtigt, jedoch die Konsistenz gewährleistet (wenn sie ordnungsgemäß verwendet wird).Verwenden Sie die zweite Option, wenn Sie die Datenkonsistenz sicherstellen möchten und jeder Thread eine aktuelle Ansicht der Karte haben muss. Verwenden Sie die erste Option, wenn die Leistung kritisch ist und jeder Thread nur Daten in die Karte einfügt, wobei Lesevorgänge seltener auftreten.
quelle
In Bezug auf den Verriegelungsmechanismus:
Hashtable
Verriegelt das Objekt , während nur der EimerConcurrentHashMap
verriegelt wird .quelle
Hashtable
sperrt keinen Teil der Karte. Schauen Sie sich die Implementierung an. Es wird einsynchronized
Schlüssel ohne Schloss verwendet, was im Grunde bedeutet, dass erhashtable
bei jedem Vorgang vollständig verriegelt wird .Die "Skalierbarkeitsprobleme" für
Hashtable
sind in genau der gleichen Weise vorhandenCollections.synchronizedMap(Map)
- sie verwenden eine sehr einfache Synchronisation, was bedeutet, dass nur ein Thread gleichzeitig auf die Karte zugreifen kann.Dies ist kein großes Problem, wenn Sie einfache Einfügungen und Suchvorgänge haben (es sei denn, Sie tun dies äußerst intensiv), wird jedoch zu einem großen Problem, wenn Sie die gesamte Karte durchlaufen müssen, was für eine große Karte lange dauern kann Ein Thread macht das, alle anderen müssen warten, wenn sie etwas einfügen oder nachschlagen wollen.
Das
ConcurrentHashMap
Verfahren verwendet sehr ausgefeilte Techniken, um die Notwendigkeit einer Synchronisation zu verringern und einen parallelen Lesezugriff durch mehrere Threads ohne Synchronisation zu ermöglichen, und bietet, was noch wichtiger ist, eineIterator
, die keine Synchronisation erfordert, und ermöglicht sogar das Ändern der Karte während der Interaktion (obwohl es keine Garantie dafür gibt, ob oder Es werden keine Elemente zurückgegeben, die während der Iteration eingefügt wurden.quelle
ConcurrentHashMap wird bevorzugt, wenn Sie es verwenden können - obwohl mindestens Java 5 erforderlich ist.
Es ist so konzipiert, dass es bei Verwendung durch mehrere Threads gut skaliert werden kann. Die Leistung ist möglicherweise geringfügig schlechter, wenn jeweils nur ein Thread auf die Karte zugreift, jedoch erheblich besser, wenn mehrere Threads gleichzeitig auf die Karte zugreifen.
Ich habe einen Blogeintrag gefunden , der eine Tabelle aus dem hervorragenden Buch Java Concurrency In Practice wiedergibt , das ich sehr empfehlen kann.
Collections.synchronizedMap ist nur dann wirklich sinnvoll, wenn Sie eine Karte mit einigen anderen Merkmalen, möglicherweise einer geordneten Karte wie einer TreeMap, abschließen müssen.
quelle
Der Hauptunterschied zwischen diesen beiden ist der
ConcurrentHashMap
nur ein Teil der Daten gesperrt wird, die aktualisiert werden, während andere Threads auf einen anderen Teil der Daten zugreifen können. AllerdingsCollections.synchronizedMap()
wird sperren Sie alle die Daten , während die Aktualisierung, die nur andere Threads können auf die Daten zugreifen , wenn die Sperre aufgehoben wird. Wenn es viele Aktualisierungsvorgänge und relativ wenige Lesevorgänge gibt, sollten Sie auswählenConcurrentHashMap
.Ein weiterer Unterschied besteht darin, dass
ConcurrentHashMap
die Reihenfolge der übergebenen Elemente in der Map nicht beibehalten wird. Dies ähnelt demHashMap
Speichern von Daten. Es gibt keine Garantie dafür, dass die Elementreihenfolge erhalten bleibt. WährendCollections.synchronizedMap()
wird die Elementreihenfolge der übergebenen Karte beibehalten. Wenn Sie beispielsweise einTreeMap
an übergebenConcurrentHashMap
, um die Elemente in demConcurrentHashMap
kann die gleiche wie die Reihenfolge , in der nicht seinTreeMap
, sondernCollections.synchronizedMap()
wird die Bestellung erhalten.Außerdem,
ConcurrentHashMap
kann garantiert werden, dass keinConcurrentModificationException
Wurf ausgelöst wird, während ein Thread die Map aktualisiert und ein anderer Thread den von der Map erhaltenen Iterator durchläuft. DiesCollections.synchronizedMap()
ist jedoch nicht garantiert.Es gibt einen Beitrag, der die Unterschiede dieser beiden und auch der
ConcurrentSkipListMap
.quelle
Synchronisierte Karte:
Synchronized Map unterscheidet sich auch nicht wesentlich von Hashtable und bietet eine ähnliche Leistung in gleichzeitigen Java-Programmen. Der einzige Unterschied zwischen Hashtable und SynchronizedMap besteht darin, dass SynchronizedMap kein Legacy ist und Sie jede Map umschließen können, um ihre synchronisierte Version mithilfe der Collections.synchronizedMap () -Methode zu erstellen.
ConcurrentHashMap:
Die ConcurrentHashMap-Klasse bietet eine gleichzeitige Version der Standard-HashMap. Dies ist eine Verbesserung der synchronizedMap-Funktionalität, die in der Collections-Klasse bereitgestellt wird.
Im Gegensatz zu Hashtable und Synchronized Map wird niemals die gesamte Karte gesperrt, sondern die Karte wird in Segmente unterteilt, und diese werden gesperrt. Es ist besser, wenn die Anzahl der Reader-Threads größer ist als die Anzahl der Writer-Threads.
ConcurrentHashMap ist standardmäßig in 16 Regionen unterteilt und Sperren werden angewendet. Diese Standardnummer kann beim Initialisieren einer ConcurrentHashMap-Instanz festgelegt werden. Beim Einstellen von Daten in einem bestimmten Segment wird die Sperre für dieses Segment erhalten. Dies bedeutet, dass zwei Aktualisierungen immer noch gleichzeitig sicher ausgeführt werden können, wenn sie sich jeweils auf separate Buckets auswirken. Dadurch werden Sperrenkonflikte minimiert und die Leistung maximiert.
ConcurrentHashMap löst keine ConcurrentModificationException aus
ConcurrentHashMap löst keine ConcurrentModificationException aus, wenn ein Thread versucht, sie zu ändern, während ein anderer darüber iteriert
Unterschied zwischen synchornizedMap und ConcurrentHashMap
Collections.synchornizedMap (HashMap) gibt eine Sammlung zurück, die fast Hashtable entspricht, wobei jeder Änderungsvorgang in Map für das Map-Objekt gesperrt ist, während im Fall von ConcurrentHashMap die Thread-Sicherheit erreicht wird, indem die gesamte Map je nach Parallelitätsstufe in verschiedene Partitionen aufgeteilt wird und nur einen bestimmten Teil sperren, anstatt die gesamte Karte zu sperren.
ConcurrentHashMap erlaubt keine Nullschlüssel oder Nullwerte, während synchronisierte HashMap einen Nullschlüssel zulässt.
Ähnliche Links
Link1
Link2
Leistungsvergleich
quelle
Hashtable
undConcurrentHashMap
erlauben Sie keinenull
Schlüssel odernull
Werte.Collections.synchronizedMap(Map)
synchronisiert alle Operationen (get
,put
,size
, usw.).ConcurrentHashMap
unterstützt die vollständige Parallelität von Abrufen und die einstellbare erwartete Parallelität für Updates.Wie üblich gibt es Kompromisse zwischen Parallelität und Overhead-Geschwindigkeit. Sie müssen wirklich die detaillierten Anforderungen an die Parallelität Ihrer Anwendung berücksichtigen, um eine Entscheidung zu treffen, und dann Ihren Code testen, um festzustellen, ob er gut genug ist.
quelle
In
ConcurrentHashMap
wird die Sperre auf ein Segment anstelle einer gesamten Karte angewendet. Jedes Segment verwaltet seine eigene interne Hash-Tabelle. Die Sperre wird nur für Aktualisierungsvorgänge angewendet.Collections.synchronizedMap(Map)
synchronisiert die gesamte Karte.quelle
Sie haben Recht
HashTable
, Sie können es vergessen.In Ihrem Artikel wird die Tatsache erwähnt, dass HashTable und die synchronisierte Wrapper-Klasse zwar grundlegende Thread-Sicherheit bieten, indem jeweils nur ein Thread auf die Map zugreifen kann. Dies ist jedoch keine "echte" Thread-Sicherheit, da für viele zusammengesetzte Vorgänge immer noch eine zusätzliche Synchronisierung erforderlich ist Beispiel:
Denken Sie jedoch nicht, dass dies
ConcurrentHashMap
eine einfache Alternative für einenHashMap
mit einem typischensynchronized
Block ist, wie oben gezeigt. Lesen Sie diesen Artikel, um die Feinheiten besser zu verstehen.quelle
Hier sind einige:
1) ConcurrentHashMap sperrt nur einen Teil der Karte, aber SynchronizedMap sperrt den gesamten MAp.
2) ConcurrentHashMap bietet eine bessere Leistung als SynchronizedMap und ist skalierbarer.
3) Bei mehreren Lesern und Einzelschreibern ist ConcurrentHashMap die beste Wahl.
Dieser Text stammt aus dem Unterschied zwischen ConcurrentHashMap und Hashtable in Java
quelle
Wir können Thread-Sicherheit erreichen, indem wir ConcurrentHashMap und synchronizedHashmap und Hashtable verwenden. Aber es gibt einen großen Unterschied, wenn man sich die Architektur ansieht.
quelle
ConcurrentHashMap
SynchronizedHashMap
Quelle
quelle
ConcurrentHashMap ist für den gleichzeitigen Zugriff optimiert.
Zugriffe sperren nicht die gesamte Karte, sondern verwenden eine feinkörnigere Strategie, die die Skalierbarkeit verbessert. Es gibt auch funktionale Verbesserungen speziell für den gleichzeitigen Zugriff, z. B. gleichzeitige Iteratoren.
quelle
Es gibt eine wichtige Funktion , die Sie beachten sollten,
ConcurrentHashMap
außer der von ihr bereitgestellten Parallelitätsfunktion, nämlich den ausfallsicheren Iterator. Ich habe Entwickler gesehen, dieConcurrentHashMap
nur verwendet haben, weil sie das Entryset bearbeiten möchten - setzen / entfernen, während sie darüber iterieren.Collections.synchronizedMap(Map)
bietet keinen ausfallsicheren Iterator, sondern einen ausfallsicheren Iterator. Fail-Fast-Iteratoren verwenden einen Schnappschuss der Kartengröße, der während der Iteration nicht bearbeitet werden kann.quelle
quelle
Wenn Sie das verwenden möchten,
ConcurrentHashMap
stellen Sie im Allgemeinen sicher, dass Sie bereit sind, Aktualisierungen zu verpassen(dh das Drucken von Inhalten der HashMap stellt nicht sicher, dass die aktuelle Karte gedruckt wird), und verwenden Sie APIs
CyclicBarrier
, um die Konsistenz über alle Programme hinweg sicherzustellen Lebenszyklus.quelle
Die Collections.synchronizedMap () -Methode synchronisiert alle Methoden der HashMap und reduziert sie effektiv auf eine Datenstruktur, in die jeweils ein Thread eintreten kann, da jede Methode für eine gemeinsame Sperre gesperrt wird.
In ConcurrentHashMap erfolgt die Synchronisation etwas anders. Anstatt jede Methode für eine gemeinsame Sperre zu sperren, verwendet ConcurrentHashMap eine separate Sperre für separate Buckets, wodurch nur ein Teil der Karte gesperrt wird. Standardmäßig gibt es 16 Eimer und separate Schlösser für separate Eimer. Die Standard-Parallelitätsstufe ist also 16. Das bedeutet, dass theoretisch zu jeder Zeit 16 Threads auf ConcurrentHashMap zugreifen können, wenn sie alle Buckets trennen.
quelle
ConcurrentHashMap wurde als Alternative zu Hashtable in Java 1.5 als Teil des Parallelitätspakets vorgestellt. Mit ConcurrentHashMap haben Sie eine bessere Wahl, nicht nur, wenn es sicher in der gleichzeitigen Multithread-Umgebung verwendet werden kann, sondern auch eine bessere Leistung als Hashtable und synchronizedMap bietet. ConcurrentHashMap bietet eine bessere Leistung, da ein Teil von Map gesperrt wird. Es ermöglicht gleichzeitige Lesevorgänge und behält gleichzeitig die Integrität bei, indem Schreibvorgänge synchronisiert werden.
Wie ConcurrentHashMap implementiert wird
ConcurrentHashMap wurde als Alternative zu Hashtable entwickelt und unterstützt alle Funktionen von Hashtable mit zusätzlichen Funktionen, der sogenannten Parallelitätsstufe. Mit ConcurrentHashMap können mehrere Leser gleichzeitig lesen, ohne Blöcke zu verwenden. Dies wird möglich, indem Map in verschiedene Teile aufgeteilt und nur ein Teil der Map in Updates blockiert wird. Standardmäßig ist die Parallelitätsstufe 16, sodass Map auf 16 Teile aufgeteilt wird und jeder Teil von einem separaten Block verwaltet wird. Dies bedeutet, dass 16 Threads gleichzeitig mit Map arbeiten können, wenn sie mit verschiedenen Teilen von Map arbeiten. Dies macht ConcurrentHashMap sehr produktiv und beeinträchtigt nicht die Thread-Sicherheit.
Wenn Sie an einigen wichtigen Funktionen von ConcurrentHashMap interessiert sind und wenn Sie diese Realisierung von Map verwenden sollten, habe ich nur einen Link zu einem guten Artikel eingefügt - So verwenden Sie ConcurrentHashMap in Java
quelle
Neben dem, was vorgeschlagen wurde, möchte ich den Quellcode veröffentlichen, der sich auf bezieht
SynchronizedMap
.Um einen
Map
Thread sicher zu machen , können wir verwendenCollections.synchronizedMap
Anweisung verwenden und die Map-Instanz als Parameter eingeben.Die Implementierung von
synchronizedMap
inCollections
ist wie folgtWie Sie sehen können, wird das Eingabeobjekt vom
Map
Objekt umschlossenSynchronizedMap
.Lassen Sie uns in die Implementierung von
SynchronizedMap
,Was
SynchronizedMap
getan werden kann, kann als Hinzufügen einer einzelnen Sperre zur primären Methode des Eingabeobjekts zusammengefasstMap
werden. Auf alle von der Sperre geschützten Methoden können nicht mehrere Threads gleichzeitig zugreifen. Das bedeutet normale Operationen wieput
undget
gleichzeitig von einem einzelnen Thread für alle Daten in der ausgeführt werden könnenMap
Objekt.Es macht das
Map
Objekt-Thread jetzt sicher, aber in einigen Szenarien kann die Leistung zu einem Problem werden.Die
ConcurrentMap
Implementierung ist weitaus komplizierter. Weitere Informationen finden Sie unter Erstellen einer besseren HashMap . Kurz gesagt, es wird unter Berücksichtigung von Thread-Sicherheit und Leistung implementiert.quelle