2011-08-13 18 views
36

El artículo de wikipedia sobre Singletons menciona algunos modos seguros de implementar la estructura en Java. Para mis preguntas, consideremos los Singletons que tienen largos procedimientos de inicialización y muchos hilos a la vez.Thread Safe Singletons en Java

En primer lugar, ¿este método no mencionado es seguro para subprocesos, y si es así, en qué se sincroniza?

public class Singleton { 
    private Singleton instance; 

    private Singleton() { 
     //lots of initialization code 
    } 

    public static synchronized Singleton getInstance() { 
     if(instance == null) { 
      instance = new Singleton(); 
     } 
     return instance; 
    } 
} 

En segundo lugar, ¿por qué el siguiente thread de implementación es seguro Y flojo en la inicialización? ¿Qué sucede exactamente si dos hilos entran en el método getInstance() al mismo tiempo?

public class Singleton { 
    private Singleton() { 
     //lots of initialization code 
    } 

    private static class SingletonHolder { 
     public static final Singleton instance = new Singleton(); 
    } 

    public static Singleton getInstance() { 
     return SingletonHolder.instance; 
    } 
} 

Por último, en el segundo ejemplo, ¿qué pasaría si un hilo obtiene una instancia primera y otro hilo obtiene una instancia y trata de realizar acciones en que antes de que el constructor ha terminado en el primer hilo? ¿Puedes entrar en un estado inseguro entonces?

Respuesta

44

Respuesta 1: static synchronized métodos utilizan el objeto de clase como el bloqueo - es decir, en este caso Singleton.class.

Respuesta 2: El lenguaje Java, entre otras cosas:

  • clases de cargas cuando se accede a la primera/usa
  • garantiza que antes de permitir el acceso a una clase, todos los inicializadores estáticos han completado

Estos dos hechos significan que la clase estática interna SingletonHolder no se carga hasta que se llama al método getInstance(). En ese momento, y antes de que el hilo que hace que la llamada tenga acceso, la instancia estática de esa clase se crea una instancia como parte de la carga de clases.

Todo esto significa que tenemos la carga diferida seguro, y sin ninguna necesidad de sincronización/cerraduras!

Este patrón es el patrón para utilizar para singletons. Es mejor que otros patrones porque MyClass.getInstance() es el estándar de la industria de facto para singletons: todos los que lo usan saben automáticamente que están tratando con un singleton (con código, siempre es bueno ser obvio), por lo que este patrón tiene la API correcta y implementación correcta bajo el capó.

btw Bill Pugh's article vale la pena leer para completar cuando se entienden los patrones de singleton.

+0

Después de leer ese artículo, ¿tengo razón al decir que Java realiza una sincronización "interna" cuando carga campos estáticos? – donnyton

+7

_ "Este patrón es el patrón que se debe usar para singletons." _ - y ¿qué pasa con [Singleum enum de Java efectivo] (http://stackoverflow.com/questions/427902/java-enum-singleton)? –

+3

El ENUM singleton en mi humilde opinión no es tan claro ni obvio como este y por lo tanto no es tan bueno: 'MyClass.getInstance()' es el estándar de la industria para singletons; todos los que lo usen automáticamente (deben) saben que están tratando un singleton. Este patrón tiene la API correcta * y * la implementación correcta bajo el capó. – Bohemian