Problema de concurrencia de Hashmap

Tengo un Hashmap que, por razones de velocidad, me gustaría no requerir el locking. ¿Actualizarlo y acceder a él al mismo tiempo causará algún problema, suponiendo que no me preocupen los datos obsoletos?

Mis accesos se obtienen, no iterando a través de él, y las eliminaciones son parte de las actualizaciones.

Sí, causará problemas importantes. Un ejemplo es lo que podría suceder al agregar un valor al mapa hash: esto puede causar una repetición de la tabla, y si eso ocurre mientras otro hilo itera sobre una lista de colisión (una tabla hash “bucket”), ese hilo podría erróneamente no puede encontrar una clave que existe en el mapa. HashMap es explícitamente inseguro para uso concurrente.

Use ConcurrentHashMap lugar.

La importancia de sincronizar o usar ConcurrentHashMap no puede subestimarse.

Estuve bajo la impresión errónea hasta hace un par de años de que podía salirme con la única sincronización de las operaciones de poner y quitar en un HashMap. Esto es, por supuesto, muy peligroso y, en realidad, da como resultado un ciclo infinito en HashMap.get () en algunos jdk (creo que a principios de los 1.5).

Lo que hice hace un par de años (y realmente no debería hacerse):

 public MyCache { private Map map = new HashMap(); public synchronzied put(String key, Object value){ map.put(key,value); } public Object get(String key){ // can cause in an infinite loop in some JDKs!! return map.get(key); } } 

EDITAR : pensé que agregaría un ejemplo de lo que no debe hacer (ver arriba)

En caso de duda, verifique los Javadocs de la clase:

Tenga en cuenta que esta implementación no está sincronizada. Si varios subprocesos acceden a un mapa hash simultáneamente, y al menos uno de los subprocesos modifica estructuralmente el mapa, debe estar sincronizado externamente. (Una modificación estructural es cualquier operación que agrega o elimina una o más asignaciones, simplemente cambiar el valor asociado con una clave que ya contiene una instancia no es una modificación estructural). Esto se logra sincronizando un objeto que naturalmente encapsula el mapa . Si no existe tal objeto, el mapa debe ser “ajustado” utilizando el método Collections.synchronizedMap. Esto se realiza mejor en el momento de la creación, para evitar el acceso no sincronizado accidental al mapa:

Map m = Collections.synchronizedMap(new HashMap(...));

(énfasis no mío)

De modo que basándote en el hecho de que dijiste que tus hilos eliminarán las asignaciones del Mapa, la respuesta es que , definitivamente causará problemas y sí, definitivamente no es seguro .

Sí. Cosas muy malas sucederán Por ejemplo, su hilo podría quedar atrapado en un ciclo infinito.

Utilice ConcurrentHashMap o NonBlockingHashMap

Las condiciones que describes no serán satisfechas por HashMap . Como el proceso de actualización de un mapa no es atómico, puede encontrar el mapa en un estado no válido. Múltiples escrituras pueden dejarlo en un estado corrupto. ConcurrentHashMap (1.5 o posterior) hace lo que quiere.

Si por ‘al mismo tiempo’ te refieres a múltiples hilos, entonces sí debes bloquear el acceso al mismo (O usa ConcurrentHashMap o similar que hace el locking por ti).

No, no habrá problemas si haces lo siguiente:

  1. Coloque sus datos en el HashMap en la primera carga de un hilo antes de que ocurra un multihilo. Esto se debe a que el proceso de agregar datos altera el número de cambio y es diferente la primera vez que lo agrega (se devolverá un valor nulo) en lugar de reemplazar los datos (se devolverán los datos anteriores, pero el número de cambio no se modificará). Modcount es lo que hace que los iteradores fallen rápidamente. Sin embargo, si usa get, no se repetirá nada, por lo que está bien.

  2. Tenga las mismas llaves en su aplicación. Una vez que la aplicación se inicia y carga sus datos, no se pueden asignar otras claves a este mapa. De esta forma, un get obtendrá datos obsoletos o datos que se insertaron frescos; no habrá problemas.

Al igual que otros usuarios, utiliza un ConcurrentHashMap o sincroniza el mapa cuando lo actualices.

Leo aquí o en otro lugar, no, no accedes desde múltiples hilos, pero nadie dice lo que realmente sucede.

Entonces, he visto hoy (es por eso que estoy en esta … vieja pregunta) en una aplicación que se ejecuta en producción desde marzo: 2 ponen el mismo HashSet (luego HashMap) causan una sobrecarga de la CPU (cerca del 100%) y la memoria aumenta de 3GB, luego abajo por GC. Tenemos que reiniciar la aplicación.