2011-08-01 18 views

Respuesta

7

El problema de simultaneidad no se bloquea, pero qué versión de los datos está viendo.

  • si la variable compartida está escrito de forma atómica, es posible que uno (lector) hilo para leer un valor rancio cuando se pensaba que su (escritor) hilo había actualizado la variable. Puede usar palabras clave volátiles para evitar que sus cadenas de lectores lean un valor obsoleto en esta situación.

  • si la operación de escritura no es atómica (por ejemplo, si se trata de un objeto compuesto de algún tipo y está escribiendo fragmentos a la vez, mientras que los otros hilos podrían leerlo teóricamente), entonces su preocupación también ya que algunos hilos de lectura podrían ver la variable en un estado incoherente. Podrías evitar esto bloqueando el acceso a la variable mientras se escribía (lento) o asegurándote de estar escribiendo atómicamente.

3

Tenga en cuenta que volátil NO es atómico, lo que significa que el doble y largo que utilizan 64 bits se puede leer en un estado incoherente donde 32 bits son el valor antiguo y 32 bits son el nuevo valor. Además, las matrices volátiles no hacen que las entradas de la matriz sean volátiles. Se recomienda encarecidamente utilizar clases de java.util.concurrent.

+1

yo no era consciente de que los dobles y los largos se pueden ver en un estado incoherente. Entonces, ¿esto también se aplica a las referencias (de 64 bits) en un sistema de 64 bits y significa que puede obtener una referencia no válida? –

+0

Los largos y los dobles inconsistentes debido a las escrituras desbloqueadas se conocen comúnmente como "desgarro prolongado". Las referencias a objetos respaldadas por un puntero de 64 bits en un jvm de 64 bits NO están sujetas a este problema. Es decir, una "escritura" de una referencia de objeto siempre es atómica. –

+4

Los valores volátiles 'long' y' double' ** son atómicos **, al contrario de los valores no volátiles 'long' y' double' (que pueden ser no atómicos). Otros valores primitivos son atómicos incluso si no son volátiles. –

4

La respuesta simple es sí, necesita sincronización.

Si alguna vez escribe en un campo y lo lee desde cualquier otro lugar sin algún tipo de sincronización, su programa puede ver un estado incoherente y es probable que esté equivocado. Su programa no se bloqueará, pero puede ver el viejo o el nuevo o (en el caso de los largos y dobles) la mitad de los datos antiguos y medianos.

Sin embargo, cuando digo "alguna forma de sincronización", me refiero más exactamente a algo que crea una relación de "sucede antes" (también conocida como barrera de memoria) entre las ubicaciones de escritura y lectura. Las clases Synchronization o java.util.concurrent.lock son la forma más obvia de crear tal cosa, pero todas las colecciones simultáneas normalmente también ofrecen garantías similares (compruebe javadoc para estar seguro). Por ejemplo, hacer una puesta en espera en una cola concurrente creará una relación de pasar antes de.

Marcar un campo como volátil le impide ver referencias inconsistentes (desgarro prolongado) y garantiza que todos los hilos "verán" una escritura. Pero las escrituras/lecturas de campos volátiles no se pueden combinar con otras operaciones en unidades atómicas más grandes. Las clases Atomic manejan operaciones combo comunes como compare-and-set o read-and-increment. Sincronización u otros sincronizadores java.util.concurrent (CyclicBarrier, etc.) o bloqueos se deben utilizar para áreas más grandes de exclusividad.

Partiendo del simple sí, hay casos que son más "no, si realmente sabes lo que estás haciendo". Dos ejemplos:

1) El caso especial de un campo que es definitivo y se escribe SÓLO durante la construcción. Un ejemplo de esto es cuando se rellena un caché precomputado (piense en un Mapa donde las claves son valores conocidos y los valores son valores derivados precalculados). Si construye eso en un campo antes de la construcción y el campo es final y nunca escribe más tarde, el final del constructor realiza la "congelación final del campo" y las lecturas posteriores NO DEBEN sincronizarse.

2) El caso del patrón "racy single check" que se trata en Java efectivo. El ejemplo canónico está en java.lang.String.código hash(). String tiene un campo hash que se calcula de forma perezosa la primera vez que llama a hashCode() y se almacena en caché en el campo local, que NO está sincronizado. Básicamente, varios subprocesos pueden competir para calcular este valor y establecerse sobre otros hilos, pero debido a que está protegido por un centinela bien conocido (0) y siempre calcula el valor idéntico (por lo que no nos importa qué hilo "gana" o si multiple do), esto en realidad está garantizado que está bien.

Una referencia más largo (escrito por mí): http://refcardz.dzone.com/refcardz/core-java-concurrency

Cuestiones relacionadas