threads thread practice example java concurrency

practice - thread java



Hashmap problema de concurrencia (9)

Tengo un Hashmap que, por razones de velocidad, me gustaría no requerir el bloqueo. ¿Actualizarlo y acceder a él al mismo tiempo causará problemas, suponiendo que no me importe la información obsoleta?

Mis accesos son recibidos, no iterando a través de ellos, y las eliminaciones son parte de las actualizaciones.


Como otros mencionaron, use un mapa de mapa concurrente o sincronice el mapa cuando lo actualice.


En caso de duda, marque los Javadocs 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 el mapa estructuralmente, debe sincronizarse externamente. (Una modificación estructural es cualquier operación que agrega o elimina una o más asignaciones; el simple hecho de cambiar el valor asociado con una clave que ya contiene una instancia no es una modificación estructural). Esto se realiza normalmente mediante la sincronización en algún objeto que encapsula el mapa de forma natural. . Si no existe tal objeto, el mapa debe "ajustarse" utilizando el método Collections.synchronizedMap. Esto se hace mejor en el momento de la creación, para evitar el acceso accidental no sincronizado al mapa:

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

(énfasis no mío)

Entonces, dado que dijiste que tus hilos eliminarán las asignaciones del Mapa, la respuesta es que definitivamente causará problemas y sí, definitivamente no es seguro .


La importancia de sincronizar o usar ConcurrentHashMap no puede ser subestimada.

Estuve bajo la impresión equivocada hasta hace un par de años de que solo podía sincronizar las operaciones de colocación y eliminación en un HashMap. Por supuesto, esto es muy peligroso y en realidad da como resultado un bucle infinito en HashMap.get () en algunos (a principios de 1.5, creo) en jdk.

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

public MyCache { private Map<String,Object> map = new HashMap<String,Object>(); 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 se debe hacer (ver arriba)


Las condiciones que usted describe no serán satisfechas por HashMap . Dado que el proceso de actualización de un mapa no es atómico, puede encontrarse con 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 quieres.


Leí aquí o en otra parte, no, no accedes desde varios subprocesos, pero nadie dice lo que realmente sucede.

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


No, no habrá problemas si haces lo siguiente:

  1. Coloque sus datos en el HashMap en la primera carga de un solo hilo antes de que ocurra cualquier multihilo. Esto se debe a que el proceso de agregar datos altera el modcount y es diferente la primera vez que lo agrega (se devolverá un nulo) en lugar de reemplazar los datos (los datos antiguos se devolverán, pero el modcount no se modificará). Modcount es lo que hace que los iteradores fracasen rápidamente. Sin embargo, si estás usando get, no se iterará nada, así que está bien.

  2. Tenga las mismas llaves en toda su aplicación. Una vez que la aplicación se inicia y carga sus datos, no se pueden asignar otras teclas a este mapa. De esta forma, una obtención obtendrá datos obsoletos o nuevos que se insertaron, no habrá problemas.



Si por ''al mismo tiempo'' te refieres a varios subprocesos, entonces sí, debes bloquear el acceso a él (o usar ConcurrentHashMap o similar que haga el bloqueo por ti).


Sí, causará grandes problemas. Un ejemplo es lo que podría suceder cuando se agrega un valor al mapa hash: esto puede causar una repetición de la tabla, y si eso ocurre mientras otro hilo está iterando sobre una lista de colisiones (un "cubo" de la tabla hash), ese hilo podría erróneamente falla al encontrar una clave que existe en el mapa. HashMap es explícitamente inseguro para el uso concurrente.

Utilice ConcurrentHashMap lugar.