El modelo de java meomry indica que los bloques synchronize
que se sincronizan en el mismo monitor imponen una antes-después-real en las variables modificadas dentro de esos bloques. Ejemplo:Modelo de memoria Java: reordenamiento y bloqueos concurrentes
// in thread A
synchronized(lock)
{
x = true;
}
// in thread B
synchronized(lock)
{
System.out.println(x);
}
En este caso está garantizada que el hilo B verá x==true
tanto tiempo como hilo A ya pasó que synchronized
-bloque. Ahora estoy en el proceso de reescribir muchos códigos para usar los bloqueos más flexibles (y se dice que son más rápidos) en java.util.concurrent
, especialmente en ReentrantReadWriteLock
. Así que el ejemplo es el siguiente:
EDITAR: El ejemplo se rompió, porque incorrectamente transformado el código, como se ha señalado por Matt B. Fijan como sigue:
// in thread A
lock.writeLock().lock();
{
x = true;
}
lock.writeLock().unlock();
// in thread B
lock.readLock().lock();
{
System.out.println(x);
}
lock.readLock().unlock();
Sin embargo, no he visto ninguna pista dentro de la especificación del modelo de memoria que tales cerraduras también implican el ordenamiento nessessary. Al observar la implementación, parece depender del acceso a las variables volátiles dentro de AbstractQueuedSynchronizer
(para la implementación del sol al menos). Sin embargo, esto no forma parte de ninguna especificación y, además, el acceso a las variables no volátiles no está realmente cubierto por la barrera de memoria que ofrecen estas variables, ¿o sí?
lo tanto, aquí están mis preguntas:
- ¿Es seguro asumir el mismo orden que con los "viejos"
synchronized
bloques? - ¿Está documentado esto en alguna parte?
- ¿Está accediendo a cualquier variable volátil una barrera de memoria para cualquier otra variable?
Saludos, Steffen
-
comentario a Yanamon:
mira el siguiente código:
// in thread a
x = 1;
synchronized (a) { y = 2; }
z = 3;
// in thread b
System.out.println(x);
synchronized (a) { System.out.println(y); }
System.out.println(z);
Por lo que entendí, la barrera de memoria hace cumplir la segunda salida para mostrar 2, pero no tiene efecto garantizado en las otras variables ...? Entonces, ¿cómo se puede comparar esto con acceder a una variable volátil?
Una nota sobre el código que ha agregado, thread b solo imprimirá 2 si obtiene el candado de un thread anterior a ... eso fue algo implícito, pero solo quería dejar eso en claro. Pero para responder a su pregunta volátil, volátil se debe utilizar de la siguiente manera para forzar la visibilidad: -------- volátil boolean memoryBarrier = false; int unguardedValue = 0; // thread a: unguardedValue = 10; memoryBarrier = true; // thread b if (memoryBarrier) { // unguardedValue se garantiza que se lee como 10; } – Yanamon
Bueno, supongo que escribir código en los comentarios realmente no funciona bien, actualicé mi respuesta con un ejemplo – Yanamon