¿Tengo que usar una implementación de mapa segura para subprocesos cuando solo leo de ella?

Si hago lo siguiente.

  • Crea un HashMap (en un campo final)
  • Rellenar HashMap
  • Envuelva HashMap con un mapa de envoltura no modificable
  • Iniciar otros hilos que accederán pero no modificarán el mapa

Según tengo entendido, el mapa se ha "publicado de forma segura" porque los otros subprocesos se iniciaron después de que el mapa se completó por completo, así que creo que está bien acceder al mapa desde varios subprocesos, ya que no se puede modificar después de este punto.

¿Es esto correcto?

preguntado el 10 de mayo de 11 a las 13:05

5 Respuestas

Esto está perfectamente bien con respecto al mapa en sí. Pero debe darse cuenta de que hacer que el mapa no sea modificable solo hará que el mapa en sí no sea modificable y no es sus claves y valores. Entonces, si tiene, por ejemplo, un Map<String, SomeMutableObject> como Map<String, List<String>>, entonces los subprocesos aún podrán alterar el valor, por ejemplo map.get("foo").add("bar");. Para evitar esto, también le gustaría hacer que las claves / valores sean inmutables / no modificables.

contestado el 10 de mayo de 11 a las 17:05

Esto es realmente importante para las claves, ya que el comportamiento de un Map no se especifica si se cambia una clave de una manera que cambia el resultado de equals. - musiKk

Lo mismo sería cierto si OP usara ConcurrentHashMap. - sombra

Según tengo entendido, el mapa se ha "publicado de forma segura" porque los otros subprocesos se iniciaron después de que el mapa se completó por completo, así que creo que está bien acceder al mapa desde varios subprocesos, ya que no se puede modificar después de este punto.

sí. Solo asegúrese de que los otros subprocesos se inicien de manera sincronizada, es decir, asegúrese de tener un relación sucede-antes entre la publicación del mapa y el inicio de los hilos.

Esto se discute en esta entrada del blog:

[...] Así es como funciona Collections.unmodifiableMap ().

[...]

Debido al significado especial de la palabra clave "final", Las instancias de esta clase se pueden compartir con varios subprocesos sin utilizar ninguna sincronización adicional.; cuando otro hilo llama a get () en la instancia, se garantiza que obtendrá el objeto que colocó en el mapa, sin realizar ninguna sincronización adicional. Probablemente debería usar algo que sea seguro para subprocesos para realizar el traspaso entre subprocesos (como LinkedBlockingQueue o algo así), pero si olvida hacer esto, aún tiene la garantía.

contestado el 10 de mayo de 11 a las 18:05

Estás en lo correcto. No es necesario garantizar el acceso exclusivo a la estructura de datos por diferentes subprocesos mediante el uso de mutex'es o de otra manera, ya que es inmutable. Por lo general, esto aumenta considerablemente el rendimiento.

También tenga en cuenta que si solo ajusta el mapa original en lugar de crear una copia, es decir, el método Map no modificable delega llamadas al método más allá del HashMap interno, la modificación del mapa subyacente puede presentar problemas de condición de carrera.

contestado el 10 de mayo de 11 a las 18:05

El mapa inmutable nace para ser seguro para subprocesos. Puede usar ImmutableMap of Guava.

contestado el 10 de mayo de 11 a las 18:05

En resumen, no, no es necesario que el mapa sea seguro para subprocesos si las lecturas no son destructivas y la referencia del mapa se publica de forma segura en el cliente.

En el ejemplo hay dos importantes sucede antes relaciones establecidas aquí. La publicación del campo final (si y solo si la población se realiza dentro del constructor y la referencia no se filtra fuera del constructor) y las llamadas para iniciar los hilos.

Cualquier cosa que modifique el mapa después de estas llamadas y que el cliente lea el mapa no se publica de forma segura.

Tenemos, por ejemplo, un CopyOnWriteMap que tiene un mapa subyacente no seguro para subprocesos que se copia en cada escritura. Esto es lo más rápido posible en situaciones en las que hay muchas más lecturas que escrituras (el almacenamiento en caché de los datos de configuración es un buen ejemplo).

Dicho esto, si la intención realmente es no cambiar el mapa, establecer una versión inmutable del mapa en el campo es siempre la mejor manera de hacerlo, ya que garantiza que el cliente verá lo correcto.

Por último, hay algunos Map implementaciones que tienen lecturas destructivas como un LinkedHashMap con orden de acceso, o un WeakHashMap donde las entradas pueden desaparecer. Estos tipos de mapas deber ser accedido en serie.

contestado el 11 de mayo de 11 a las 02:05

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.