2012-05-14 21 views
7

Ich habe irgendwo gelesen, dass in ConcurrentHashMap das gesamte Map-Objekt nicht gesperrt ist und stattdessen eine Sperre für einen Teil der Map gemacht wird.ConcurrentHashMap Sperren

Kann jemand näher erläutern, wann kommt das Verriegeln ins Bild?

Ist es richtig, dass beim Lesen der Map keine Sperrung involviert ist, aber während der Aktualisierung wird nur das Locking verwendet?

+3

Dieser Artikel sollte helfen: http://www.ibm.com/developerworks/java/library/j-jtp08223/ – yegor256

+1

Die [Javadoc] (http://docs.oracle.com/javase/7/docs/ api/java/util/concurrent/ConcurrentHashMap.html) erklärt die Implementierung ziemlich detailliert. – trutheality

Antwort

12

Ja, ConcurrentHashMap verwendet eine Vielzahl von Sperren, jede Sperre steuert ein Segment des Hashs.

Beim Festlegen von Daten in einem bestimmten Segment wird die Sperre für dieses Segment erhalten.

Beim Abrufen von Daten wird ein flüchtiger Lesevorgang verwendet. Wenn das flüchtige Lesen zu einem Fehlschlag führt, wird die Sperre für das Segment für einen letzten Versuch eines erfolgreichen Lesevorgangs erhalten.

+1

Ich habe nicht "wenn das If das flüchtige Lesen führt zu einem Miss, dann wird die Sperre für das Segment für einen letzten Versuch eines erfolgreichen Lese abgerufen". Kannst du bitte etwas im Detail erklären? – Anand

+1

@anand Gemäß dem JMM ist es möglich, dass das flüchtige Schreiben eines Felds im Konstruktor für Threads sichtbar ist, nachdem das Objekt die Konstruktion beendet hat und für andere Threads sichtbar ist (dies gilt nicht für letzte Felder). Die Sperre, auf die er sich bezieht, sorgt dafür, dass es passiert - bevor der flüchtige Schreibvorgang bei anderen Lesevorgängen erfolgt. Hinweis: Dies konnte passieren, darf aber nie vorkommen und ich habe es in Java 6 nie lesen können - da wurde gerade wegen der ganzen Verwirrung davon geredet, es einfach zu entfernen. –

+2

Und nur um klar zu machen, Konstruktor Abschluss bezieht sich auf den Eintrag des Eimers. –

5

Die Verriegelung wird so weit wie möglich minimiert, während sie weiterhin threadsicher ist.

Um zu erklären, dass "ein Teil der Map gesperrt ist" bedeutet dies, dass beim Aktualisieren nur ein "1/concurrencyLevel" der Map (basierend auf einem Hash des Schlüssels) gesperrt wird. Dies bedeutet, dass zwei Updates immer noch gleichzeitig sicher ausgeführt werden können, wenn sie jeweils separate "Buckets" betreffen, wodurch die Sperrkonflikte minimiert und die Leistung maximiert wird.

Noch wichtiger ist, vertrauen Sie der JDK-Implementierung - Sie sollten sich keine Gedanken über Implementierungsdetails im JDK machen müssen (zum einen kann es von Release zu Release wechseln). Konzentrieren Sie sich stattdessen einfach auf Ihren Code.

+0

Wenn Sie Hashtable verknüpfen, meinen Sie ConcurrentHashMap. Ihre Erklärung ist sonst falsch. Die gesamte Hashtable-Instanz wird für jede Änderung oder jeden Lesevorgang synchronisiert. –

+0

@JohnVint Danke. Ich habe meine Antwort aktualisiert. – Bohemian

+0

@trutheality Danke. Ich habe meine Antwort korrigiert. – Bohemian

0

ConcurrentHashMap Reentrant Lock-Mechanismus verwenden. ConcurrentHashMap verwendet Segmente anstelle von Buckets. Wenn neue Datensätze die Insert-Sperre erhalten, werden nur Segmente und nicht die vollständige Liste der Segmente erfasst. Also hier macht die Idee klar, dass Multi-Level-Lock auf dem gleichen erwerben wird.

Da kein Concurrency-Level festgelegt wurde, wird die ConcurrentHashMap in 16 Segmente unterteilt. Und jedes Segment fungiert als unabhängige HashMap.

Bei der Leseoperation in ConcurrentHashMap wird keine Sperre angewendet.

Verwandte Themen