thread safe example current concurrent java concurrency java.util.concurrent concurrenthashmap

example - java map thread safe



Necesita una explicación simple de cómo funciona el "trazado de bandas" con ConcurrentHashMap (3)

De acuerdo con Java Concurrency in Practice, el capítulo 11.4.3 dice:

La división de bloqueo a veces se puede extender al bloqueo de partición en un conjunto de objetos independientes de tamaño variable, en cuyo caso se denomina división de bloqueo. Por ejemplo, la implementación de ConcurrentHashMap utiliza una matriz de 16 bloqueos, cada uno de los cuales protege 1/16 de los cubos de hash; La cubeta N está protegida por el bloqueo N mod 16.

Todavía tengo problemas para entender y visualizar el mecanismo de corte de líneas y cubos. ¿Alguien puede explicar esto con buenas palabras de comprensión :)

Gracias por adelantado.


El concepto clave aquí es el "cubo". en lugar de usar un bloqueo global para todo este hash Table, usa un pequeño bloqueo para cada grupo. También es un buen análogo al ordenamiento de cubetas que puede mejorar la complejidad de clasificación.


El mapa hash se basa en una matriz, donde la función hash asigna un objeto a un elemento en la matriz subyacente. Digamos que la matriz subyacente tiene 1024 elementos: ConcurrentHashMap realmente convierte esto en 16 subarreglos diferentes de 64 elementos, por ejemplo, {0, 63}, {64, 127}, etc. La sub-matriz {0, 63} no afecta a la sub-matriz {64, 127} - un subproceso puede escribir en la primera sub-matriz mientras que otro subproceso escribe en la segunda sub-matriz.


La diferencia entre el bloqueo en un Collections.synchronizedMap() y un ConcurrentHashMap es la siguiente:

Si varios subprocesos accederán a un Collections.synchronizedMap() frecuencia, habrá mucha contención ya que cada método se sincroniza mediante un bloqueo compartido (es decir, si el subproceso X llama a un método en Collections.synchronizedMap() , todos los demás subprocesos serán bloqueado para que no llame a ningún método en un Collections.synchronizedMap() hasta que el hilo X regrese del método al que llamó

Un ConcurrentHashMap tiene un número variable de bloqueos (el valor predeterminado es 16) que cada uno guarda un segmento de las claves en el ConcurrentHashMap . Así que para un ConcurrentHashMap con 160 teclas, cada cerradura guardará 10 elementos. Por lo tanto, los métodos que operan en una clave ( get , put , set , etc.) solo bloquean el acceso a otros métodos que operan en una clave donde las claves están en el mismo segmento. Por ejemplo, si el subproceso X llama a put(0, someObject) , y luego el subproceso Y llama a put(10, someOtherObject) esas llamadas pueden ejecutarse simultáneamente, y el subproceso Y no tiene que esperar a que el subproceso X regrese de put(0, someObject) . A continuación se proporciona un ejemplo.

Además, ciertos métodos como size() e isEmpty() no están protegidos en absoluto. Si bien esto permite una mayor concurrencia, significa que no son muy consistentes (no reflejarán el estado que está cambiando simultáneamente).

public static void main(String[] args) { ConcurrentHashMap<Integer, Object> map = new ConcurrentHashMap<>(160); new Thread(new Runnable() { @Override public void run() { map.put(0, "guarded by one lock"); } }.start(); new Thread(new Runnable() { @Override public void run() { map.put(10, "guarded by another lock"); } }.start(); new Thread(new Runnable() { @Override public void run() { // could print 0, 1, or 2 System.out.println(map.count()); } }.start(); }