synchronizedmap - ¿ConcurrentHashMap en Java?
thread safe hashmap (5)
1.ConcurrentHashMap es seguro para subprocesos y es el código al que se puede acceder mediante un solo subproceso a la vez.
2.ConcurrentHashMap sincroniza o bloquea en cierta parte del mapa. Para optimizar el rendimiento de ConcurrentHashMap, Map se divide en diferentes particiones en función del nivel de concurrencia. Para que no tengamos que sincronizar todo el objeto del mapa.
3.El nivel de concurrencia predeterminado es 16, por lo que el mapa se divide en 16 partes y cada parte se rige con un bloqueo diferente que significa que 16 hilos pueden operar.
4.ConcurrentHashMap no permite valores NULL. Así que la clave no puede ser nula en ConcurrentHashMap.
¿Cuál es el uso de ConcurrentHashMap
en Java? ¿Cuáles son sus beneficios? ¿Como funciona? Código de ejemplo sería útil también.
El punto es proporcionar una implementación de HashMap
que sea segura para subprocesos. Varios subprocesos pueden leer y escribir en él sin la posibilidad de recibir datos obsoletos o dañados. ConcurrentHashMap
proporciona su propia sincronización, por lo que no tiene que sincronizar los accesos de forma explícita.
Otra característica de ConcurrentHashMap
es que proporciona el método putIfAbsent
, que agregará un mapeo atómicamente si la clave especificada no existe. Considere el siguiente código:
ConcurrentHashMap<String, Integer> myMap = new ConcurrentHashMap<String, Integer>();
// some stuff
if (!myMap.contains("key")) {
myMap.put("key", 3);
}
Este código no es seguro para subprocesos, ya que otro subproceso puede agregar una asignación para "key"
entre la llamada a los contains
y la llamada a put
. La implementación correcta sería:
myMap.putIfAbsent("key", 3);
Puede ser utilizado para la memorización:
import java.util.concurrent.ConcurrentHashMap;
public static Function<Integer, Integer> fib = (n) -> {
Map<Integer, Integer> cache = new ConcurrentHashMap<>();
if (n == 0 || n == 1) return n;
return cache.computeIfAbsent(n, (key) -> HelloWorld.fib.apply(n - 2) + HelloWorld.fib.apply(n - 1));
};
Realmente la gran diferencia funcional es que no lanza una excepción y / o termina dañada cuando alguien más la cambia mientras la estás usando.
Con las colecciones regulares, si otro subproceso agrega o elimina un elemento mientras tiene acceso (a través del iterador), generará una excepción. ConcurrentHashMap les permite hacer el cambio y no detiene su hilo.
Tenga en cuenta que no ofrece ningún tipo de garantías de sincronización o promesas sobre la visibilidad en un momento dado del cambio de un hilo a otro. (Es algo así como un aislamiento de base de datos de lectura confirmada, en lugar de un mapa sincronizado que se comporta más como un aislamiento de base de datos serializable. (Bloqueo de filas SQL de la vieja escuela serializable, no multiversión de Oracle-ish serializable :))
El uso más común que conozco es en el almacenamiento en caché de información derivada inmutable en entornos de Servidores de Aplicaciones donde muchos subprocesos pueden tener acceso a la misma cosa, y realmente no importa si dos de ellos calculan el mismo valor de caché y lo ponen dos veces porque se intercalan , etc. (por ejemplo, se usa ampliamente dentro del marco de Spring WebMVC para mantener configuraciones derivadas de tiempo de ejecución como asignaciones de URL a métodos de manejo).
ConcurrentHashMap
permite el acceso simultáneo al mapa. HashTables también ofrece acceso sincronizado al mapa, pero todo el mapa está bloqueado para realizar cualquier operación.
La lógica detrás de ConcurrentHashMap es que your entire table is not getting locked
, sino solo la porción [ segments
]. Cada segmento gestiona su propia HashTable. El bloqueo se aplica solo para actualizaciones. En caso de recuperaciones, permite plena concurrencia.
Tomemos cuatro hilos trabajando simultáneamente en un mapa cuya capacidad es de 32, la tabla se divide en cuatro segmentos donde cada segmento administra una tabla hash de capacidad. La colección mantiene una lista de 16 segmentos de forma predeterminada, cada uno de los cuales se utiliza para proteger (o bloquear) un solo grupo del mapa.
Esto significa efectivamente que 16 hilos pueden modificar la colección a la vez. Este nivel de concurrencia se puede aumentar usando el argumento opcional de constructor concurrencyLevel .
public ConcurrentHashMap(int initialCapacity,
float loadFactor, int concurrencyLevel)
Como se indicó en la otra respuesta, ConcurrentHashMap ofrece el nuevo método putIfAbsent()
que es similar a poner, excepto que el valor no se anulará si existe la clave.
private static Map<String,String> aMap =new ConcurrentHashMap<String,String>();
if(!aMap.contains("key"))
aMap.put("key","value");
El nuevo método también es más rápido, ya que evita el double traversing
como el anterior. contains
método tiene que ubicar el segmento e iterar la tabla para encontrar la clave y, nuevamente, el método put
debe atravesar el grupo y la clave.