Tengo un mapa que debe ser modificado por varios hilos al mismo tiempo.
Parece que hay tres implementaciones de mapas sincronizados diferentes en la API de Java:
Hashtable
Collections.synchronizedMap(Map)
ConcurrentHashMap
Por lo que entiendo, Hashtable
es una implementación antigua (que amplía la Dictionary
clase obsoleta ), que se ha adaptado más tarde para adaptarse a la Map
interfaz. Si bien está sincronizado, parece tener serios problemas de escalabilidad y se desaconseja para nuevos proyectos.
¿Pero qué hay de los otros dos? ¿Cuáles son las diferencias entre los mapas devueltos por Collections.synchronizedMap(Map)
y ConcurrentHashMap
s? ¿Cuál se ajusta a qué situación?
java
dictionary
concurrency
Henning
fuente
fuente
ConcurrentSkipListMap
como otraMap
implementación segura para subprocesos . Diseñado para ser altamente concurrente bajo carga, utilizando el algoritmo Skip List .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 asegurará la coherencia (si se usa correctamente).Utilice la segunda opción si necesita garantizar la coherencia de los datos y cada subproceso debe tener una vista actualizada del mapa. Use el primero si el rendimiento es crítico, y cada hilo solo inserta datos en el mapa, con lecturas que ocurren con menos frecuencia.
fuente
Respecto al mecanismo de bloqueo:
Hashtable
bloquea el objeto , mientrasConcurrentHashMap
que solo bloquea el cubo .fuente
Hashtable
no está bloqueando la parte del mapa. Mira la implementación. Utiliza unasynchronized
llave sin bloqueo, por lo que básicamente significa que se bloquea por completohashtable
en cada operación.Los "problemas de escalabilidad"
Hashtable
están presentes exactamente de la misma maneraCollections.synchronizedMap(Map)
: usan una 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 tiene inserciones y búsquedas simples (a menos que lo haga con mucha intensidad), pero se convierte en un gran problema cuando necesita iterar sobre todo el Mapa, lo que puede llevar mucho tiempo para un Mapa grande, mientras que un hilo hace eso, todos los demás tienen que esperar si quieren insertar o buscar algo.
Los
ConcurrentHashMap
usos muy sofisticadas técnicas para reducir la necesidad de sincronización y permitir el acceso de lectura en paralelo de múltiples hilos sin sincronización y, más importante, proporciona unaIterator
que no requiere la sincronización e incluso permite que el mapa se modifica durante iteración (a pesar de que no ofrece ninguna garantía o no se devolverán los elementos que se insertaron durante la iteración).fuente
Se prefiere ConcurrentHashMap 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 peor cuando solo un subproceso accede al Mapa a la vez, pero significativamente mejor cuando varios subprocesos acceden al mapa simultáneamente.
Encontré una entrada de blog que reproduce una tabla del excelente libro Java Concurrency In Practice , que recomiendo ampliamente.
Collections.synchronizedMap tiene sentido realmente solo si necesita envolver un mapa con otras características, tal vez algún tipo de mapa ordenado, como un TreeMap.
fuente
La principal diferencia entre estos dos es que
ConcurrentHashMap
bloqueará solo una parte de los datos que se están actualizando, mientras que otros hilos pueden acceder a otra parte de los datos. Sin embargo,Collections.synchronizedMap()
bloqueará todos los datos durante la actualización, otros subprocesos solo pueden acceder a los datos cuando se libera el bloqueo. Si hay muchas operaciones de actualización y una cantidad relativamente pequeña de operaciones de lectura, debe elegirConcurrentHashMap
.También otra diferencia es que
ConcurrentHashMap
no conservará el orden de los elementos en el mapa pasado. Es similarHashMap
al almacenamiento de datos. No hay garantía de que se conserve el orden de los elementos. MientrasCollections.synchronizedMap()
que preservará el orden de los elementos del Mapa pasado. Por ejemplo, si pasa unTreeMap
aConcurrentHashMap
, el orden de los elementos en elConcurrentHashMap
puede no ser el mismo que el orden en elTreeMap
, peroCollections.synchronizedMap()
conservará el orden.Además,
ConcurrentHashMap
puede garantizar que no seConcurrentModificationException
arroje mientras un hilo actualiza el mapa y otro hilo atraviesa el iterador obtenido del mapa. Sin embargo,Collections.synchronizedMap()
no está garantizado en esto.Hay una publicación que demuestra las diferencias de estos dos y también el
ConcurrentSkipListMap
.fuente
Mapa sincronizado:
El Mapa sincronizado tampoco es muy diferente de Hashtable y proporciona un rendimiento similar en programas Java concurrentes. La única diferencia entre Hashtable y SynchronizedMap es que SynchronizedMap no es un legado y puede ajustar cualquier Mapa para crear su versión sincronizada utilizando el método Collections.synchronizedMap ().
ConcurrentHashMap:
La clase ConcurrentHashMap proporciona una versión concurrente del HashMap estándar. Esta es una mejora en la funcionalidad sincronizada de mapas proporcionada en la clase Colecciones.
A diferencia del Mapa Hashtable y el Mapa Sincronizado, nunca bloquea todo el Mapa, sino que divide el mapa en segmentos y el bloqueo se realiza en esos. Funciona mejor si el número de hilos de lectura es mayor que el número de hilos de escritura.
ConcurrentHashMap de forma predeterminada se separa en 16 regiones y se aplican bloqueos. Este número predeterminado se puede establecer al inicializar una instancia de ConcurrentHashMap. Cuando se configuran datos en un segmento particular, se obtiene el bloqueo para ese segmento. Esto significa que dos actualizaciones aún pueden ejecutarse simultáneamente de manera segura si cada una afecta a depósitos separados, minimizando así la contención de bloqueo y maximizando así el rendimiento.
ConcurrentHashMap no produce una excepción ConcurrentModificationException
ConcurrentHashMap no arroja una ConcurrentModificationException si un hilo intenta modificarlo mientras otro está iterando sobre él
Diferencia entre synchornizedMap y ConcurrentHashMap
Collections.synchornizedMap (HashMap) devolverá una colección que es casi equivalente a Hashtable, donde todas las operaciones de modificación en Map están bloqueadas en el objeto Map mientras que en el caso de ConcurrentHashMap, la seguridad del subproceso se logra dividiendo Map completo en una partición diferente según el nivel de concurrencia y solo bloqueando una parte particular en lugar de bloquear todo el Mapa.
ConcurrentHashMap no permite claves nulas o valores nulos, mientras que HashMap sincronizado permite claves nulas.
Enlaces similares
Enlace1
Link2
Comparación de rendimiento
fuente
Hashtable
yConcurrentHashMap
no permitirnull
claves onull
valores.Collections.synchronizedMap(Map)
sincroniza todas las operaciones (get
,put
,size
, etc.).ConcurrentHashMap
admite total concurrencia de recuperaciones y concurrencia esperada ajustable para actualizaciones.Como de costumbre, hay concesiones de concurrencia, gastos generales y velocidad involucrados. Realmente necesita considerar los requisitos detallados de concurrencia de su aplicación para tomar una decisión, y luego probar su código para ver si es lo suficientemente bueno.
fuente
En
ConcurrentHashMap
, el bloqueo se aplica a un segmento en lugar de un mapa completo. Cada segmento gestiona su propia tabla hash interna. El bloqueo se aplica solo para las operaciones de actualización.Collections.synchronizedMap(Map)
sincroniza todo el mapa.fuente
Tienes razón
HashTable
, puedes olvidarte de eso.Su artículo menciona el hecho de que, si bien HashTable y la clase de envoltura sincronizada proporcionan seguridad básica de subprocesos al permitir solo un subproceso a la vez para acceder al mapa, esto no es seguridad de subprocesos 'verdadera' ya que muchas operaciones compuestas aún requieren sincronización adicional, para ejemplo:
Sin embargo, no piense que
ConcurrentHashMap
es una alternativa simple para un bloqueHashMap
típicosynchronized
como se muestra arriba. Lea este artículo para comprender mejor sus complejidades.fuente
Aquí hay algunos:
1) ConcurrentHashMap bloquea solo una parte del mapa, pero SynchronizedMap bloquea todo el mapa.
2) ConcurrentHashMap tiene un mejor rendimiento sobre 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
fuente
Podemos lograr la seguridad del subproceso utilizando ConcurrentHashMap y sincronizedHashmap y Hashtable. Pero hay mucha diferencia si nos fijamos en su arquitectura.
fuente
ConcurrentHashMap
SynchronizedHashMap
fuente
fuente
ConcurrentHashMap está optimizado para acceso concurrente.
Los accesos no bloquean todo el mapa, pero utilizan una estrategia más precisa, que mejora la escalabilidad. También hay mejoras funcionales específicas para el acceso concurrente, por ejemplo, iteradores concurrentes.
fuente
Hay una característica crítica a tener en cuenta
ConcurrentHashMap
aparte de la característica de concurrencia que proporciona, que es un iterador a prueba de fallas . He visto a los desarrolladores usarConcurrentHashMap
solo porque quieren editar el conjunto de entrada: poner / quitar mientras itera sobre él.Collections.synchronizedMap(Map)
no proporciona un iterador a prueba de fallas, pero sí proporciona un iterador rápido a prueba de fallas . Los iteradores de falla rápida utilizan una instantánea del tamaño del mapa que no se puede editar durante la iteración.fuente
fuente
En general, si desea utilizar el,
ConcurrentHashMap
asegúrese de estar listo para perderse las 'actualizaciones'(es decir, imprimir el contenido de HashMap no garantiza que imprimirá el Mapa actualizado) y utilizar API como
CyclicBarrier
para garantizar la coherencia en todo el programa ciclo vital.fuente
El método Collections.synchronizedMap () sincroniza todos los métodos de HashMap y efectivamente lo reduce a una estructura de datos donde puede ingresar un hilo a la vez porque bloquea todos los métodos en un bloqueo común.
En ConcurrentHashMap, la sincronización se realiza de manera un poco diferente. En lugar de bloquear todos los métodos en un bloqueo común, ConcurrentHashMap usa un bloqueo separado para cubos separados, bloqueando así solo una parte del Mapa. Por defecto, hay 16 cubos y también cerraduras separadas para cubos separados. Por lo tanto, el nivel de concurrencia predeterminado es 16. Eso significa que, en teoría, en cualquier momento dado, 16 subprocesos pueden acceder a ConcurrentHashMap si todos van a separarse.
fuente
ConcurrentHashMap se presentó como alternativa a Hashtable en Java 1.5 como parte del paquete de concurrencia. Con ConcurrentHashMap, tiene una mejor opción no solo si se puede usar de manera segura en el entorno concurrente de subprocesos múltiples, sino que también proporciona un mejor rendimiento que Hashtable y synchronizedMap. ConcurrentHashMap funciona mejor porque bloquea una parte de Map. Permite operaciones de lectura concurrentes y al mismo tiempo mantiene la integridad sincronizando las operaciones de escritura.
Cómo se implementa ConcurrentHashMap
ConcurrentHashMap se desarrolló como alternativa de Hashtable y admite todas las funcionalidades de Hashtable con una capacidad adicional, llamada nivel de concurrencia. ConcurrentHashMap permite que varios lectores lean simultáneamente sin usar bloques. Se hace posible separando el Mapa en diferentes partes y bloqueando solo una parte del Mapa en las actualizaciones. De forma predeterminada, el nivel de concurrencia es 16, por lo que Map se divide en 16 partes y cada parte se gestiona mediante un bloque separado. Significa que 16 hilos pueden trabajar con Map simultáneamente, si funcionan con diferentes partes de Map. Hace que ConcurrentHashMap sea muy productivo y no reduce la seguridad de los subprocesos.
Si está interesado en algunas características importantes de ConcurrentHashMap y cuándo debe usar esta realización de Map, acabo de poner un enlace a un buen artículo: Cómo usar ConcurrentHashMap en Java
fuente
Además de lo sugerido, me gustaría publicar el código fuente relacionado
SynchronizedMap
.Para que un
Map
subproceso sea seguro, podemos usar laCollections.synchronizedMap
instrucción e ingresar la instancia del mapa como parámetro.La implementación de
synchronizedMap
enCollections
es como a continuaciónComo puede ver, el
Map
objeto de entrada está envuelto por elSynchronizedMap
objeto.Vamos a profundizar en la implementación de
SynchronizedMap
,Lo
SynchronizedMap
que se puede resumir es agregar un solo bloqueo al método primario delMap
objeto de entrada . Múltiples hilos al mismo tiempo no pueden acceder a todos los métodos protegidos por el bloqueo. Eso significa que las operaciones normales comoput
yget
pueden ser ejecutadas por un solo hilo al mismo tiempo para todos los datos en elMap
objeto.Ahora hace que el
Map
subproceso del objeto sea seguro, pero el rendimiento puede convertirse en un problema en algunos escenarios.La
ConcurrentMap
implementación es mucho más complicada, podemos referirnos a Crear un mejor HashMap para más detalles. En pocas palabras, se implementa teniendo en cuenta tanto el subproceso seguro como el rendimiento.fuente