Pregunta ¿Cuál es la diferencia entre ConcurrentHashMap y Collections.synchronizedMap (Map)?


Tengo un Mapa que debe ser modificado por varios hilos al mismo tiempo.

Parece que hay tres implementaciones diferentes de mapas sincronizados en la API de Java:

  • Hashtable
  • Collections.synchronizedMap(Map)
  • ConcurrentHashMap

Por lo que entiendo, Hashtable es una implementación antigua (que extiende el obsoleto Dictionary clase), que se ha adaptado más tarde para adaptarse al Map interfaz. Mientras es sincronizado, parece tener graves problemas de escalabilidad y se desanima para nuevos proyectos.

Pero, ¿y los otros dos? ¿Cuáles son las diferencias entre los mapas devueltos por Collections.synchronizedMap(Map) y ConcurrentHashMaps? ¿Cuál se ajusta a qué situación?


523
2018-02-04 09:22


origen


Respuestas:


Para sus necesidades, use ConcurrentHashMap. Permite la modificación concurrente del Mapa desde varios hilos sin la necesidad de bloquearlos. Collections.synchronizedMap(map) crea un mapa de bloqueo que degradará el rendimiento, aunque garantizará la coherencia (si se usa correctamente).

Use la segunda opción si necesita garantizar la coherencia de los datos, y cada hilo debe tener una vista actualizada del mapa. Utilice el primero si el rendimiento es crítico, y cada hilo solo inserta datos en el mapa, con lecturas que suceden con menos frecuencia.


372
2018-02-04 09:32



╔═══════════════╦═══════════════════╦═══════════════════╦═════════════════════╗
║   Property    ║     HashMap       ║    Hashtable      ║  ConcurrentHashMap  ║
╠═══════════════╬═══════════════════╬═══════════════════╩═════════════════════╣ 
║      Null     ║     allowed       ║              not allowed                ║
║  values/keys  ║                   ║                                         ║
╠═══════════════╬═══════════════════╬═════════════════════════════════════════╣
║Is thread-safe ║       no          ║                  yes                    ║
╠═══════════════╬═══════════════════╬═══════════════════╦═════════════════════╣
║     Lock      ║       not         ║ locks the whole   ║ locks the portion   ║        
║  mechanism    ║    applicable     ║       map         ║                     ║ 
╠═══════════════╬═══════════════════╩═══════════════════╬═════════════════════╣
║   Iterator    ║               fail-fast               ║ weakly consistent   ║ 
╚═══════════════╩═══════════════════════════════════════╩═════════════════════╝

En cuanto al mecanismo de bloqueo: Hashtable  bloquea el objeto, mientras ConcurrentHashMap cabellos solo el cubo.


200
2017-07-21 20:09



Los "problemas de escalabilidad" para Hashtable están presentes exactamente de la misma manera en Collections.synchronizedMap(Map) - usan sincronización muy simple, lo que significa que solo un hilo puede acceder al mapa al mismo tiempo.

Esto no es un gran problema cuando tienes insertos y búsquedas simples (a menos que lo hagas de manera extremadamente intensiva), pero se convierte en un gran problema cuando necesitas recorrer todo el mapa, lo que puede llevar mucho tiempo para un mapa grande, mientras un hilo hace eso, todos los demás tienen que esperar si quieren insertar o buscar algo.

los ConcurrentHashMap utiliza técnicas muy sofisticadas para reducir la necesidad de sincronización y permitir el acceso de lectura paralelo por varios hilos sin sincronización y, lo que es más importante, proporciona una Iterator eso no requiere sincronización e incluso permite que el Mapa se modifique durante la interacción (aunque no garantiza si los elementos insertados durante la iteración serán devueltos o no).


127
2018-02-04 09:43



ConcurrentHashMap es preferido cuando puede usarlo, aunque requiere al menos Java 5.

Está diseñado para escalar bien cuando es usado por múltiples hilos. El rendimiento puede ser marginalmente más pobre cuando solo un subproceso accede al Mapa a la vez, pero es significativamente mejor cuando varios subprocesos acceden al mapa al mismo tiempo.

Encontre un Entrada de blog que reproduce una tabla del excelente libro Concurrencia de Java en la práctica, que recomiendo completamente

Collections.synchronizedMap tiene sentido realmente solo si necesita envolver un mapa con algunas otras características, tal vez algún tipo de mapa ordenado, como un TreeMap.


31
2018-02-04 09:34



La principal diferencia entre estos dos es que ConcurrentHashMap bloqueará solo una parte de los datos que se actualizan, mientras que otros subprocesos pueden acceder a otra porción de datos. Sin embargo, Collections.synchronizedMap() bloqueará todos los datos durante la actualización, otros subprocesos solo podrán acceder a los datos cuando se libere el bloqueo. Si hay muchas operaciones de actualización y una cantidad relativamente pequeña de operaciones de lectura, debe elegir ConcurrentHashMap.

También otra diferencia es que ConcurrentHashMap no conservará el orden de los elementos en el Mapa pasado. Es similar a HashMap al almacenar datos. No hay garantía de que se preserve el orden de los elementos. Mientras Collections.synchronizedMap() preservará el orden de los elementos del Mapa pasado. Por ejemplo, si pasa un TreeMap a ConcurrentHashMap, el orden de los elementos en el ConcurrentHashMap puede no ser el mismo que el orden en el TreeMap, pero Collections.synchronizedMap() preservará el orden

Además, ConcurrentHashMap puede garantizar que no hay ConcurrentModificationException lanzado mientras un hilo está actualizando el mapa y otro hilo está atravesando el iterador obtenido del mapa. Sin embargo, Collections.synchronizedMap() no está garantizado en esto.

Ahi esta una publicación que demuestran las diferencias de estos dos y también la ConcurrentSkipListMap.


29
2017-11-16 15:53



En ConcurrentHashMap, el bloqueo se aplica a un segmento en lugar de a un Mapa completo. Cada segmento maneja su propia tabla hash interna. El bloqueo se aplica solo para las operaciones de actualización. Collections.synchronizedMap(Map) sincroniza todo el mapa


12
2017-10-28 18:00



Como de costumbre, hay simultaneidad, intercambios de velocidad de sobrecarga implicados. Realmente necesita considerar los requisitos de concurrencia detallados de su aplicación para tomar una decisión, y luego probar su código para ver si es lo suficientemente bueno.


11
2018-02-04 09:36



Tienes razón sobre HashTable, puedes olvidarte de eso.

Tu artículo menciona el hecho de que aunque HashTable y la clase contenedora sincronizada brindan seguridad básica de hilos al permitir solo un hilo a la vez acceder al mapa, esto no es 'verdadero' seguridad de hilos ya que muchas operaciones compuestas aún requieren sincronización adicional, por ejemplo:

synchronized (records) {
  Record rec = records.get(id);
  if (rec == null) {
      rec = new Record(id);
      records.put(id, rec);
  }
  return rec;
}

Sin embargo, no pienses ConcurrentHashMap es una alternativa simple para un HashMap con un típico synchronized bloquear como se muestra arriba. Leer esta artículo para comprender mejor sus complejidades.


9
2018-02-04 09:38



Aquí hay algunos:

1) ConcurrentHashMap bloquea solo una parte de Map, pero SynchronizedMap bloquea todo MAp.
2) ConcurrentHashMap tiene un mejor rendimiento que SynchronizedMap y es más escalable.
3) En caso de lector múltiple y escritor único, ConcurrentHashMap es la mejor opción.

Este texto es de Diferencia entre ConcurrentHashMap y hashtable en Java


7
2017-11-24 07:32



Podemos lograr seguridad de subprocesos utilizando ConcurrentHashMap y synchronizedHashmap y Hashtable. Pero hay una gran diferencia si miras su arquitectura.

  1. synchronizedHashmap y Hashtable

Ambos mantendrán el bloqueo en el nivel del objeto. Entonces, si desea realizar cualquier operación como put / get, primero debe adquirir el candado. Al mismo tiempo, otros hilos no pueden realizar ninguna operación. Entonces, a la vez, solo un hilo puede operar en esto. Entonces, el tiempo de espera aumentará aquí. Podemos decir que el rendimiento es relativamente bajo cuando se compara con ConcurrentHashMap.

  1. ConcurrentHashMap

Mantendrá el bloqueo a nivel de segmento. Tiene 16 segmentos y mantiene el nivel de concurrencia como 16 por defecto. Entonces, a la vez, 16 subprocesos pueden funcionar en ConcurrentHashMap. Además, la operación de lectura no requiere un bloqueo. Entonces, cualquier número de subprocesos puede realizar una operación de obtención en él.

Si thread1 quiere realizar la operación put en el segmento 2 y thread2 quiere realizar la operación put en el segmento 4, entonces está permitido aquí. Significa que 16 subprocesos pueden realizar operaciones de actualización (put / delete) en ConcurrentHashMap a la vez.

Para que el tiempo de espera sea menor aquí. Por lo tanto, el rendimiento es relativamente mejor que el sincronizado Hashmap y Hashtable.


7
2018-03-09 13:12