java - safe - ¿Cómo usar y establecer el nivel de concurrencia apropiado para ConcurrentHashMap?
java map thread safe (4)
Estoy trabajando con alrededor de 1000 elementos en el mapa de mapa simultáneo. El nivel de concurrencia predeterminado es 16. ¿Alguien me puede ayudar con algún algoritmo o factores a partir de los cuales puedo identificar el nivel de concurrencia adecuado para mi escenario o de qué manera un nivel de concurrencia afecta el procesamiento de múltiples hilos?
ConcurrentHashMap<String, String> map=new ConcurrentHashMap<String, String>(500,1,20);
20 es mi nivel de concurrencia (valor ficticio). Necesito configurar esto de manera eficiente
16 es el número predeterminado de regiones en las que se dividirá su mapa. ConcurrentHashMap, en el caso de hilos de lectura, se realiza (en casi todos los casos) sin bloqueo en absoluto. El número de hilos de escritura es lo que necesita para preocuparse. Y este número debe ser igual al número de regiones que tiene.
ConcurrentHashMap permite que varios lectores lean simultáneamente sin ningún bloqueo. Esto se logra dividiendo el Mapa en diferentes partes según el nivel de concurrencia y bloqueando solo una parte del Mapa durante las actualizaciones. El nivel de concurrencia predeterminado es 16 y, en consecuencia, el mapa se divide en 16 partes y cada parte se rige con un bloqueo diferente. Esto significa que 16 hilos pueden operar en el Mapa simultáneamente, hasta que estén operando en diferentes partes del Mapa. Esto hace que ConcurrentHashMap sea de alto rendimiento a pesar de mantener intacta la seguridad de los hilos.
Java 8:
Ahora, ConcurrentHashMap
no utiliza en absoluto un esquema de bandas de bloqueo fijo, en su lugar, cada depósito sirve como una "banda" que utiliza la sincronización intrínseca.
Código de origen:
/** Implementation for put and putIfAbsent */
final V putVal(K key, V value, boolean onlyIfAbsent) {
...
Node<K,V> f; int n, i, fh;
...
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
...
synchronized (f) {
...
}
}
Y el constructor tiene el parámetro, solo úselo como sugerencia de tamaño, como dicen los documentos.
concurrencyLevel: el número estimado de subprocesos que se actualizan simultáneamente. La implementación puede usar este valor como una sugerencia de tamaño.
Y la fuente:
public ConcurrentHashMap(int initialCapacity,
float loadFactor, int concurrencyLevel) {
if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)
throw new IllegalArgumentException();
if (initialCapacity < concurrencyLevel) // Use at least as many bins
initialCapacity = concurrencyLevel; // as estimated threads
long size = (long)(1.0 + (long)initialCapacity / loadFactor);
int cap = (size >= (long)MAXIMUM_CAPACITY) ?
MAXIMUM_CAPACITY : tableSizeFor((int)size);
this.sizeCtl = cap;
}
Por lo tanto, no necesita considerarlo usted mismo, ConcurrentHashMap
lo manejará por usted.
Según los documentos:
La concurrencia permitida entre las operaciones de actualización está guiada por el argumento opcional de constructor
concurrencyLevel
(valor predeterminado16
), que se usa como una sugerencia para el tamaño interno . La tabla está particionada internamente para intentar permitir el número indicado de actualizaciones simultáneas sin disputa. Debido a que la ubicación en las tablas hash es esencialmente aleatoria, la concurrencia real variará. Idealmente, debería elegir un valor para acomodar tantos subprocesos como siempre modificará la tabla al mismo tiempo. El uso de un valor significativamente más alto del que necesita puede desperdiciar espacio y tiempo, y un valor significativamente menor puede llevar a la contención de hilos.
Así que necesitas responder una pregunta:
¿Cuál es el número de subprocesos que alguna vez modificarán la tabla de forma simultánea?