Pregunta

¿Este código resuelve el problema del bloqueo de doble verificación en Java?

public class DBAccessService() {
    private static DBAccessService INSTANCE;  

    private DBAccessService() {}

    public static DBAccessService getInstance() {
        if (INSTANCE != null) {
            return INSTANCE;
        }
        return createInstance();
    }

    private static synchronized DBAccessService createInstance() {
        if (INSTANCE != null) {
            return INSTANCE;
        }
        DBAccessService instance = new DBAccessService();
        INSTANCE = instance;

        return INSTANCE;
    }
}

Hay 2 aspectos a prestar atención:

  1. getInstance() es no sincronizado, por lo que después de inicializar INSTANCE no hay costo por la sincronización
  2. createInstance() está sincronizado

Entonces, la pregunta es:¿Este código tiene algún problema?¿Es legal y siempre ¿a salvo de amenazas?

¿Fue útil?

Solución

para resolver esta pregunta en particular concurrencia de Java en la práctica (escrito por el equipo que básicamente escribió el java.util .conCurrent Library) recomienda la Inicialización perezosa Titular de la clase Idiom (página 348 en mi copia, listado 16.6, no 16.7)

@ThreadSafe
public class DBAccessServiceFactory {
  private static class ResourceHolder {
    public static DBAccessService INSTANCE = new DBAccessService();
  }
  public static DBAccessService getResource() {
    return ResourceHolder.INSTANCE;
  }
}

Esto es siempre legal y de seguridad. No soy un experto, así que no puedo decir que esto es mejor que su código. Sin embargo, dado que es el patrón recomendado por Doug Lea y Joshua Bloch, siempre lo usaría sobre el código que usted o yo hemos inventado, ya que es tan fácil cometer errores (como lo demuestra el número de respuestas incorrectas a esta pregunta. ).

relacionado con el problema volátil que dicen:

Los cambios posteriores en JMM (JAVA 5.0 y posteriores) han permitido trabajar DCL si el recurso se hace volátil ... Sin embargo, el IDIOM de la inicialización perezosa ofrece los mismos beneficios y es más fácil de entender.

Otros consejos

Necesitas declarar INSTANCE como volatile para que funcione:

private static volatile DBAccessService INSTANCE;

Tenga en cuenta que sólo funciona con Java 5 y posteriores.Ver La declaración "El bloqueo doblemente verificado está roto".

en este artículo se dice que "dobleEl registro comprobado "no es un problema si usa una clase Singleton Separe Singleton:

public class DBAccessHelperSingleton {
    public static DBAccessHelper instance = new DBAccessHelper(); 
} 

Tiene la misma ventaja: el campo no se instancie antes de ser referencias la primera vez.

Como se indica anteriormente, si desea mantenerlo como si lo tiene, falta volatile, en caso de que solo esté dirigido a JDK>= 5.

se ve bien. Si hay dos hilos, llame a GetInstance () y la instancia no está inicializada, solo un hilo podrá proceder con CreateInstance () y el segundo ya verá que la instancia no es NULL.

Lo único es la palabra clave volatile, por ejemplo.De lo contrario, Java puede caché.

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