ejercicios - patrones de diseño java
¿Cuál es el punto de hacer que la instancia de Singleton sea volátil al usar doble bloqueo? (5)
Lo volatile
evita que se vuelvan a ordenar las escrituras en la memoria, lo que hace imposible que otros subprocesos lean campos sin inicializar de su singleton a través del puntero del singleton.
Considere esta situación: el hilo A descubre que uniqueInstance == null
, se bloquea, confirma que todavía es null
y llama al constructor de singleton. El constructor realiza una escritura en el miembro XYZ
dentro de Singleton y regresa. El hilo A ahora escribe la referencia al singleton recién creado en uniqueInstance
y se prepara para liberar su bloqueo.
Al igual que el hilo A se prepara para liberar su bloqueo, el hilo B aparece y descubre que uniqueInstance
no es null
. El subproceso B
accede a uniqueInstance.XYZ
pensando que se ha inicializado, pero debido a que la CPU ha reordenado las escrituras, los datos que el subproceso A ha escrito en XYZ
no se han hecho visibles al subproceso B. Por lo tanto, el subproceso B ve un valor incorrecto dentro de XYZ
. Cuál está mal.
Cuando marca uniqueInstance
volatile, se inserta una barrera de memoria . Todas las escrituras iniciadas antes de uniqueInstance
se completarán antes de que se modifique uniqueInstance
, evitando la situación de reordenamiento descrita anteriormente.
Esta pregunta ya tiene una respuesta aquí:
private volatile static Singleton uniqueInstance
En un singleton cuando se usa el método de doble bloqueo para la sincronización, ¿por qué se declara la instancia única como volátil? ¿Puedo lograr la misma funcionalidad sin declararla como volátil?
Para evitar el uso de doble bloqueo, o volátil uso el siguiente
enum Singleton {
INSTANCE;
}
Crear la instancia es simple, lento y seguro para subprocesos.
Puedes usar el siguiente código:
private static Singleton uniqueInstance;
public static synchronized Singleton getInstance(){
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance
}
Sin volatile
el código no funciona correctamente con múltiples hilos.
Del bloqueo de doble comprobación de Wikipedia:
A partir de J2SE 5.0, este problema se ha solucionado. La palabra clave volátil ahora garantiza que varios subprocesos manejen la instancia de singleton correctamente. Este nuevo idioma se describe en la declaración "El bloqueo de doble comprobación está roto" :
// Works with acquire/release semantics for volatile
// Broken under Java 1.4 and earlier semantics for volatile
class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
Helper result = helper;
if (result == null) {
synchronized(this) {
result = helper;
if (result == null) {
helper = result = new Helper();
}
}
}
return result;
}
// other functions and members...
}
En general, debe evitar la verificación de bloqueo si es posible, ya que es difícil hacerlo bien y si lo hace mal puede ser difícil encontrar el error. Pruebe este enfoque más simple en su lugar:
Si el objeto auxiliar es estático (uno por cargador de clases), una alternativa es la inicialización en el idioma del titular de la demanda
// Correct lazy initialization in Java
@ThreadSafe
class Foo {
private static class HelperHolder {
public static Helper helper = new Helper();
}
public static Helper getHelper() {
return HelperHolder.helper;
}
}
La escritura en un campo volátil ocurrirá antes de cualquier operación de lectura. A continuación se muestra un código de ejemplo para una mejor comprensión:
private static volatile ResourceService resourceInstance;
//lazy Initialiaztion
public static ResourceService getInstance () {
if (resourceInstance == null) { // first check
synchronized(ResourceService.class) {
if (resourceInstance == null) { // double check
// creating instance of ResourceService for only one time
resourceInstance = new ResourceService ();
}
}
}
return resourceInstance;
}
Este enlace puede servirle mejor http://javarevisited.blogspot.com/2011/06/volatile-keyword-java-example-tutorial.html