¿Por qué se rompe el bloqueo de doble comprobación en Java?
Esta pregunta se relaciona con el comportamiento de las versiones antiguas de Java y las implementaciones antiguas del algoritmo de bloqueo de doble verificación
Nuevas implementacionesutilizarvolatile
y confiar en ligeramente cambiadovolatile
semántica, entonces sonno roto.
Se afirma que la asignación de campos siempre es atómica, excepto para campos largos o dobles.
Pero, cuando leo una explicación de por qué el bloqueo de doble verificación está roto, se dice que el problema está en la operación de asignación:
// Broken multithreaded version
// "Double-Checked Locking" idiom
class Foo {
private Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null) {
helper = new Helper();
}
}
}
return helper;
}
// other functions and members...
}
El subproceso A observa que el valor no se inicializa, por lo que obtiene el bloqueo y comienza a inicializar el valor.Debido a la semántica de algunos lenguajes de programación, el código generado por el compilador puede actualizar la variable compartida para apuntar a un objeto parcialmente construido antes de que A haya terminado de realizar la inicialización.El subproceso B se da cuenta de que la variable compartida se ha inicializado (o eso parece) y devuelve su valor. Como el subproceso B cree que el valor ya está inicializado, no adquiere el bloqueo. Si B usa el objeto antes de que B vea toda la inicialización realizada por A (ya sea porque A no ha terminado de inicializarlo o porque algunos de los valores inicializados en el objeto aún no se han filtrado a la memoria que B usa (coherencia de caché)) , el programa probablemente se bloqueará.(dehttp://en.wikipedia.org/wiki/Double-checked_locking)
Cuando es posible ¿Es posible que en la operación de asignación JVM de 64 bits no sea atómica? En caso negativo, ¿está realmente roto el "bloqueo de doble verificación"?