Pregunta

Al usar cualquiera de las clases de Java.util.concurrent, ¿todavía necesito sincronizar el acceso en la instancia para evitar problemas de visibilidad entre los hilos de diferencia?

Elaborar la pregunta un poco más

Al usar una instancia de java.util.concurrent, ¿es posible que un hilo modifique la instancia (es decir, coloque un elemento en un hashmap concurrente) y un hilo posterior no verá la modificación?

Mi pregunta surge del hecho de que el modelo de memoria Java permite que los subprocesos almacenen en caché los valores en lugar de obtenerlos directamente de la memoria si el acceso al valor no se sincroniza.

¿Fue útil?

Solución

En el paquete java.util.concurrent Propiedades de consistencia de memoria, puede consultar la API Javadoc para el paquete:

Los métodos de todas las clases en java.util.concurrent y sus subpackages extienden estas garantías a la sincronización de nivel superior. En particular:

  • Acciones en un hilo antes de colocar un objeto en cualquier colección concurrente suceder antes Acciones posteriores al acceso o eliminación de ese elemento de la colección en otro hilo.
    [...]
  • Acciones antes de "liberar" métodos de sincronizador como
    Lock.unlock, Semaphore.elease y
    CountdownLatch.Countdown
    suceder antes Acciones posteriores a un método exitoso de "adquirir" como Lock.Lock, Semaphore.Acquire, Condition.Await y CountdownLatch.Await en el mismo objeto de sincronizador en otro hilo.
    [...]

Entonces, las clases en este paquete se aseguran de la concurrencia, haciendo uso de un conjunto de clases para el control de subprocesos (Lock, Semaphore, etc.). Estas clases manejan el suceder antes lógica programáticamente, es decir, administrar una pila FIFO de hilos concurrentes, bloquear y liberar hilos actuales y posteriores (es decir, usar Thread.wait() y Thread.resume(), etc.

Luego, (teóricamente) no necesita sincronizar sus declaraciones que acceden a estas clases, porque controlan el acceso concurrente de los hilos mediante programación.

Otros consejos

Debido a que el ConcurrentHashmap (por ejemplo) está diseñado para usarse a partir de un contexto concurrente, no necesita sincronizarlo aún más. De hecho, hacerlo podría socavar las optimizaciones que introduce.

Por ejemplo, la colección.synchronizedMap (...) representa una forma de hacer que un hilo de mapa sea seguro, según tengo entendido, funciona esencialmente envolviendo todas las llamadas dentro de la palabra clave sincronizada. Algo como concurrenthashmap, por otro lado, crea "cubos" sincronizados en los elementos de la colección, causando un control de concurrencia de grano más fino y, por lo tanto, dan menos contención de bloqueo bajo un uso pesado. Es posible que tampoco se bloquee las lecturas, por ejemplo. Si lo envuelve nuevamente con algún acceso sincronizado, podría socavar esto. Obviamente, debe tener cuidado de que todo el acceso a la colección sea sincronizado, etc., que es otra ventaja de la biblioteca más nueva; No tienes que preocuparte (¡tanto!).

Las colecciones Java.Lang.Concurrent pueden implementar la seguridad de su hilo a través de Syncrhonised. en cuyo caso la especificación del idioma garantiza la visibilidad. Pueden implementar cosas sin usar cerraduras. No soy tan claro en esto, pero supongo que la misma visibilidad estaría en su lugar aquí.

Si está viendo lo que parece actualizaciones perdidas en su código, puede ser que sea solo una condición de carrera. Algo así como el concurrenthashpmap le dará el valor más reciente en una lectura y la escritura aún no se ha escrito. A menudo es una compensación entre precisión y rendimiento.

La cuestión es; java.util.concurrent cosas están destinadas a hacer estas cosas para que esté seguro de que garantiza la visibilidad y el uso de sincronización volátil y/o adicional no debería ser necesaria.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top