thread synchronizedmap safe example current concurrent java concurrenthashmap

java - synchronizedmap - thread safe hashmap



¿Por qué ConcurrentHashMap evita claves y valores nulos? (6)

El JavaDoc de ConcurrentHashMap dice esto:

Al igual que Hashtable diferencia de HashMap , esta clase no permite utilizar null como clave o valor.

Mi pregunta: ¿por qué?

2da pregunta: ¿por qué Hashtable no permite nulo?

He usado muchos HashMaps para almacenar datos. Pero cuando cambio a ConcurrentHashMap, me metí varias veces en problemas debido a NullPointerExceptions.


ConcurrentHashMap es seguro para subprocesos. Creo que no permitir claves y valores nulos fue una parte de asegurarse de que sea seguro para subprocesos.


Creo que es, al menos en parte, para permitirle combinar containsKey y get en una sola llamada. Si el mapa puede contener valores nulos, no hay forma de saber si get devuelve un valor nulo porque no hubo una clave para ese valor, o simplemente porque el valor era nulo.

¿Por que eso es un problema? Porque no hay una manera segura de hacerlo tú mismo. Toma el siguiente código:

if (m.containsKey(k)) { return m.get(k); } else { throw new KeyNotPresentException(); }

Como m es un mapa simultáneo, la clave k puede eliminarse entre containsKey y get llamadas, lo que hace que este fragmento devuelva un valor nulo que nunca estuvo en la tabla, en lugar de la KeyNotPresentException deseada.

Normalmente lo resolverías sincronizando, pero con un mapa simultáneo que, por supuesto, no funcionará. Por lo tanto, la firma de get tuvo que cambiar, y la única manera de hacerlo en una forma compatible con versiones anteriores era evitar que el usuario inserte valores nulos en primer lugar, y continuar usándolo como marcador de posición para "clave no encontrada".


Josh Bloch diseñó HashMap ; Doug Lea diseñó ConcurrentHashMap . Espero que no sea calumnioso. En realidad, creo que el problema es que los valores nulos a menudo requieren envolverse para que el valor nulo real pueda ser sin inicializar. Si el código del cliente requiere valores nulos, entonces puede pagar el costo (por cierto pequeño) de envolver los valores nulos.


No puedes sincronizar en un nulo.

Editar: Esto no es exactamente el motivo en este caso. Inicialmente pensé que había algo sofisticado en bloquear las cosas con las actualizaciones simultáneas o usar el monitor de objetos para detectar si algo se había modificado, pero al examinar el código fuente parece que estaba equivocado, se bloquean usando un "segmento" basado en una máscara de bits del hash.

En ese caso, sospecho que lo hicieron para copiar Hashtable, y sospecho que Hashtable lo hizo porque en el mundo de las bases de datos relacionales, null! = Null, por lo que usar un nulo como clave no tiene sentido.


Supongo que el siguiente fragmento de la documentación de la API da una buena pista: "Esta clase es totalmente interoperable con Hashtable en programas que dependen de la seguridad de sus hilos, pero no de sus detalles de sincronización".

Probablemente solo querían hacer que ConcurrentHashMap totalmente compatible / intercambiable con Hashtable . Y como Hashtable no permite claves y valores nulos ...


Del autor del mismo ConcurrentHashMap (Doug Lea) :

La razón principal de que los nulos no estén permitidos en ConcurrentMaps (ConcurrentHashMaps, ConcurrentSkipListMaps) es que las ambigüedades que pueden ser apenas tolerables en los mapas no concurrentes no se pueden acomodar. La principal es que si map.get(key) devuelve null , no puede detectar si la clave se asigna explícitamente a null la clave no está asignada. En un mapa no simultáneo, puede verificar esto mediante map.contains(key) , pero en uno concurrente, el mapa podría haber cambiado entre llamadas.