Si tengo dos subprocesos múltiples que acceden a un HashMap, pero les garantizo que nunca accederán a la misma clave al mismo tiempo, ¿podría eso conducir a una condición de carrera?¿Es HashMap seguro para subprocesos para diferentes claves?
Respuesta
En respuesta @ de dotsid dice esto:
Si cambia un HashMap de algún modo, tu código simplemente está roto.
Él es correcto.Un HashMap que se actualiza sin sincronización romperá incluso si los hilos están utilizando conjuntos de claves disjuntos. Estas son algunas de las cosas que pueden salir mal.
Si un hilo hace un
put
, a continuación, otro hilo puede ver un valor rancio para el tamaño del mapa hash.Cuando un hilo hace un
put
que desencadena una reconstrucción de la tabla, otro hilo puede ver las versiones transitorias o obsoletas de la referencia del conjunto de tablas hashtable, su tamaño, su contenido o las cadenas hash. Caos puede seguir.Cuando un hilo hace un
put
para una llave que choca con alguna clave utilizada por algún otro hilo, y el último hilo hace unput
por su clave, entonces el último podría ver una copia rancio de referencia cadena hash. Caos puede seguir.Cuando un hilo explora la tabla con una tecla que colisiona con una de las claves de otro hilo, puede encontrar esa clave en la cadena. Llamará a iguales en esa clave, y si los hilos no están sincronizados, el método igual puede encontrar estado obsoleto en esa clave.
Y si tiene dos hilos simultáneamente haciendo put
o remove
solicitudes, hay numerosas oportunidades para las condiciones de carrera.
puedo pensar en tres soluciones:
- Utilice un
ConcurrentHashMap
. - Use un
HashMap
regular, pero sincronícelo en el exterior; p.ej. utilizando mutexes primitivos,Lock
objetos, etcétera. - Utilice un
HashMap
diferente para cada hilo. Si los hilos realmente tienen un conjunto de claves disjuntas, entonces no debería haber necesidad (desde una perspectiva algorítmica) de que compartan un solo Mapa. De hecho, si sus algoritmos involucran a los hilos que iteran las claves, valores o entradas del mapa en algún punto, dividir el mapa individual en múltiples mapas podría dar una aceleración significativa para esa parte del procesamiento.
Depende de lo que quiere decir con "acceder". Si acaba de leer, puede leer incluso las mismas claves, siempre y cuando la visibilidad de los datos garantizados por las reglas "happens-before". Esto significa que HashMap
no debe cambiar y todos los cambios (construcciones iniciales) deben completarse antes de que el lector comience a acceder al HashMap
.
Si cambia un HashMap
de alguna manera, su código simplemente se rompe. @Stephen C brinda una muy buena explicación de por qué.
EDITAR: Si el primer caso es su situación real, le recomiendo que use Collections.unmodifiableMap()
para asegurarse de que su HashMap nunca se modifique. Los objetos apuntados por HashMap
no deberían cambiar también, por lo que agresivo al usar la palabra clave final
puede ayudarlo.
Y como dice @Lars Andren, ConcurrentHashMap
es la mejor opción en la mayoría de los casos.
¿Qué tal ConcurrentHashMap? –
ConcurrentHashMap es la mejor opción en mi opinión. La única razón por la que no lo recomendé, debido a que el autor no lo preguntó :) Tiene menos rendimiento debido a las operaciones de CAS, pero como la regla de oro de la programación simultánea dice: "Hacer las cosas bien, y solo entonces hacer es rápido ":) –
' no modificableMapa' asegura que el cliente no puede cambiar el mapa. No hace nada para garantizar que el mapa subyacente no se modifique. –
Simplemente use un ConcurrentHashMap. El ConcurrentHashMap utiliza bloqueos múltiples que cubren una gama de cubos hash para reducir las posibilidades de que se impugne un bloqueo. Hay un impacto marginal en el rendimiento para adquirir un bloqueo no impugnado.
Para responder a su pregunta original: Según el javadoc, siempre que la estructura del mapa no cambie, usted está bien. Esto significa que no se eliminarán elementos y no se agregarán nuevas claves que aún no estén en el mapa. Reemplazar el valor asociado con las claves existentes está bien.
Si varios subprocesos acceden simultáneamente a un mapa hash y al menos uno de los subprocesos modifica estructuralmente el mapa, debe estar sincronizado externamente. (Una modificación estructural es cualquier operación que añade o elimina una o más asignaciones; cambiando simplemente el valor asociado con una clave que una instancia ya contiene no es una modificación estructural.)
A pesar de que no ofrece ninguna garantía sobre la visibilidad. Entonces, debes estar dispuesto a aceptar la recuperación de asociaciones obsoletas ocasionalmente.
+1 para la precisión técnica (si no es la mejor práctica :-) – finnw
La modificación de un HashMap sin una sincronización adecuada entre dos hilos puede conducir fácilmente a una condición de carrera.
- Cuando un
put()
conduce a un cambio de tamaño de la tabla interna, esto lleva un tiempo y el otro hilo continúa escribiendo en la mesa de edad. - Dos
put()
para diferentes claves dan lugar a una actualización del mismo depósito si las claves de las claves son iguales al tamaño de la tabla. (En realidad, la relación entre el código hash y el índice de cubo es más complicado, pero todavía se puede producir colisiones.)
- 1. NSTimer ¿es seguro para subprocesos?
- 2. ¿PrintWriter es seguro para subprocesos?
- 3. Enum.TryParse - ¿es seguro para subprocesos?
- 4. ¿Es PHP seguro para subprocesos?
- 5. ¿MongoDB es seguro para subprocesos?
- 6. ¿Es itertools seguro para subprocesos?
- 7. ¿DWScript es seguro para subprocesos?
- 8. ¿SQLite.Net es seguro para subprocesos?
- 9. ¿Es System.ServiceModel.Channels.BufferManager seguro para subprocesos?
- 10. ¿HttpContext.Current.Cache es seguro para subprocesos?
- 11. ¿SecureRandom es seguro para subprocesos?
- 12. ¿Stream.Write es seguro para subprocesos?
- 13. EventAggregator, ¿es seguro para subprocesos?
- 14. Log4Net FileAppender no es seguro para subprocesos?
- 15. ¿Este código es seguro para subprocesos? ¿Cómo puedo hacer que sea seguro para subprocesos?
- 16. guava-libraries: ¿es Iterators.cycle() seguro para subprocesos?
- 17. ¿Es TimeZone de Java seguro para subprocesos?
- 18. Java Transport.send() ¿es seguro para subprocesos?
- 19. C socket API es seguro para subprocesos?
- 20. ¿List-it() es seguro para subprocesos?
- 21. C++ Segmento seguro para subprocesos
- 22. C# Singleton seguro para subprocesos
- 23. Integración de Spring & Tika: ¿mi enfoque es seguro para subprocesos?
- 24. malloc() no es reentrante pero es seguro para subprocesos?
- 25. ¿El operador de preincremento es seguro para subprocesos?
- 26. ¿Log4j no es seguro para subprocesos después de todo?
- 27. ¿El operador + = es seguro para subprocesos en Python?
- 28. ¿Por qué este código no es seguro para subprocesos?
- 29. Fábrica de objetos singleton: ¿este código es seguro para subprocesos?
- 30. ¿El retorno de rendimiento en C# es seguro para subprocesos?
4. Utilice un HashMap regular y use un ReentrantReadWriteLock para permitir múltiples concurrentes lectores, pero exclusividad para escribir operaciones. –
Subcase de 2. :-) No creo que haya ninguna necesidad de enumerar las diversas formas en que uno puede sincronizar el acceso a un HashMap regular. –
¿Se puede usar ** el bloque ** sincronizado para esto? –