Nachteil der steigenden Anzahl von Partitionen in Java ConcurrentHashMap?

8

Java ConcurrentHashMap verwaltet Partitionen intern. Jede Partition kann separat gesperrt werden. Es kann Szenarien geben, in denen alle Schlüssel, auf die mehrere Threads zugreifen, in dieselbe Partition fallen und Partitionen nicht hilfreich sein können. Das Erhöhen der Anzahl der Partitionen sollte die Gleichzeitigkeit verbessern.

Warum stellt Java den Standardwert für die Partitionsanzahl als 16 statt als sehr hohen Wert bereit? Was ist bei einer großen Anzahl von Partitionen in der Map zu hören?

    
saurabh 21.06.2013, 11:16
quelle

2 Antworten

6
  

Warum stellt Java den Standardwert für die Anzahl der Partitionen als 16 statt als sehr hohen Wert zur Verfügung?

Es ist sehr selten, dass diese vielen CPUs (die Anzahl der Threads ist nicht so wichtig) dieselbe CHM zur selben Zeit benutzt. Wenn Sie das wirklich brauchen, gibt es normalerweise eine bessere Möglichkeit, Ihre Anwendung zu schreiben, die dies vermeidet.

Angenommen, Sie haben 1000 Threads, aber nur 8 CPUs. Dies bedeutet, dass nur maximal 8 Threads ausgeführt werden und auf das CHM zugreifen, vorausgesetzt, dass Ihr Programm z. alles andere.

In realen Programmen wird selten eine Sammlung mehr als 10% der Zeit verwendet. Dies liegt daran, dass normalerweise einige I / O involviert sind, oder es ist sinnvoll, Threads zu restrukturieren, um eigene Kopien von Sammlungen zu verwenden und sie am Ende zusammen zu sammeln, z. Map-Reduce

  

Was ist die Leistung bei einer großen Anzahl von Partitionen in der Map zu hören?

Sie verschwenden ein wenig Speicher, was nicht wichtig ist, aber meistens verschwenden Sie einen L1-Cache, der auf 32 KB und eine relativ wertvolle Ressource beschränkt ist.

    
Peter Lawrey 21.06.2013 11:22
quelle
2

Hier ist was das Javadoc sagt (Java 6):

  

"Die zulässige Parallelität zwischen Update-Operationen wird durch das optionale concurrencyLevel-Konstruktorargument (Standard 16) bestimmt, das als Hinweis für die interne Dimensionierung verwendet wird. Die Tabelle ist intern partitioniert, um die angegebene Anzahl gleichzeitig zuzulassen Da die Platzierung in Hashtabellen im Wesentlichen zufällig ist, variiert die tatsächliche Parallelität.Im Idealfall sollten Sie einen Wert auswählen, der so viele Threads berücksichtigt, wie Sie die Tabelle gleichzeitig ändern.Wenn Sie einen wesentlich höheren Wert verwenden, als Sie benötigen, kann Speicherplatz verschwendet werden und Zeit, und ein signifikant niedrigerer Wert kann zu Threadkonflikten führen.Überschätzen und Unterschätzungen innerhalb einer Größenordnung haben jedoch normalerweisekeine merkliche Auswirkung.Ein Wert von eins ist angemessen, wenn bekannt ist, dass nur ein Thread modifiziertwird und alle anderen nur lesen. Auch das Ändern der Größe dieser oder einer anderen Art von Hashtabelle ist eine relativ langsame Operation, daher ist es, wenn möglich, eine gute Idee, Schätzungen von e bereitzustellen Tabellengrößen in Konstruktoren. "

Die kurze Antwort lautet also, dass der Standardwert (16) ein Kompromiss zwischen begrenzter Nebenläufigkeit und Platzverschwendung ist. Ein "sehr hoher" Wert würde viel Platz verschwenden. (Und wie Peter Lawrey bemerkt, kann dies aufgrund von Memory-Cache-Effekten zu einer Leistungsminderung führen.)

Die andere Sache, die zu beachten ist, ist, dass die LinkedHashMap Implementierung den Wert von concurrencyLevel bei 2 16 stillschweigend kappt. (Zumindest ist es das, was der Java 6-Code tut.) Es ist schwer, sich ein realistisches Szenario vorzustellen, in dem Sie so viel Parallelität benötigen würden.

    
Stephen C 21.06.2013 11:30
quelle