2010-12-19 11 views
10

Duplicar posibles:
Efficient way to implement singleton pattern in JavaThread Safe ¿Manera eficiente de implementar un patrón singleton en Java?

que estaba leyendo este Best Singleton Implementation In Java, pero no es seguro para subprocesos.

Según wiki:

if(singleton==null) { synchronized(Singleton.class) { // this is needed if two threads are waiting at the monitor at the // time when singleton was getting instantiated if(singleton==null) singleton= new Singleton(); }
}

Pero encontrar utilidad Errores da dos errores en este : 1. Verifique nula. 2. Inicialización errónea incorrecta del campo estático.

¿Cuál es la mejor manera,

¿es correcto:

synchronized (Singleton.class) { 
if (singleton== null) { 
singleton= new Singleton(); 
} 
} 
+1

Este es un duplicado de la pregunta anterior; ver esa pregunta para más detalles. Pero no estoy seguro de que esa pregunta tenga estos enlaces útiles, así que: [Acerca del bloqueo doblemente comprobado en Java] (http://www.ibm.com/developerworks/java/library/j-dcl.html) que enlaza con [estos] (http://www.ibm.com/developerworks/library/j-jtp02244.html) [dos] (http://www.ibm.com/developerworks/library/j-jtp03304/) actualizaciones para Java 5. Ver también [artículo de Wikipedia sobre bloqueo con doble verificación] (http://en.wikipedia.org/wiki/Double-checked_locking). Pero para la respuesta real a su pregunta, vea la pregunta vinculada anteriormente. –

Respuesta

20

La forma más eficiente/sencilla de hacer una carga lenta Singleton es sólo

enum Singleton { 
    INSTANCE 
} 

Nota: no es necesario bloquear ya que la carga de clase es segura para subprocesos. La clase es definitiva por defecto y el constructor no se puede llamar mediante reflexión. El INSTANCE no se creará hasta que INSTANCE o la clase se use. Si te preocupa que la clase se use accidentalmente, puedes envolver el singleton en una clase interna.

final class Singleton { 
    private Singleton() { } 
    static class SingletonHolder { 
     static final Singleton INSTANCE = new Singleton(); 
    } 
    public static Singleton getInstance() { 
     return SingletonHolder.INSTANCE; 
    } 
} 

En mi humilde opinión, tiene que ser bastante paranoico para considerar esta una mejor solución.

+0

En tu segundo código no estás usando 'enum' pero estás usando' clase', así que estoy confundido sobre cómo tomarlo. Quiero hacer una enumeración para inicializar una clase una vez y llamar a ese objeto cada vez. ¿Cómo puedo hacer eso? ¿Puede dar un ejemplo en detalle? – manish

+0

@Manish En ese caso, use un 'enum' como lo hago en el primer ejemplo. –

+0

yah está bien, pero ¿cómo puedo inicializar una clase una sola vez y usar esa instancia cada vez que uso 'enum'. esa es mi confusión.every donde acabo de ver 'enum Singleton { INSTANCE }' esto pero no cómo llamar e inicializar el objeto – manish

2

El primer ejemplo de código en la respuesta aceptada para Efficient way to implement singleton pattern in Javaes thread safe. La creación del INSTANCE es realizada por el cargador de clases la primera vez que se carga la clase; se realiza una sola vez, y de una manera segura para los subprocesos:

public final class Foo { 

    private static final Foo INSTANCE = new Foo(); 

    private Foo() { 
     if (INSTANCE != null) { 
       throw new IllegalStateException("Already instantiated"); 
     } 
    } 

    public static Foo getInstance() { 
     return INSTANCE; 
    } 
} 

(copiado de What is an efficient way to implement a singleton pattern in Java?)

El segundo ejemplo de código en la pregunta es correcta y segura para los subprocesos, pero hace que la sincronización en cada llamada a getInstance(), que afecta el rendimiento.

+0

No proteger al constructor privado es bastante paranoico. Supongo que es para evitar crear otra instancia utilizando la reflexión, ¿o es para detener las clases internas que llaman al constructor? –

+0

Estaba discutiendo una respuesta de una pregunta anterior, así que copié el código tal como está. Personalmente, omitiría la comprobación 'if (INSTANCE! = Null)' también. –

+0

y por lo tanto la excepción que supongo. ;) –

3

Mucho se ha escrito sobre este tema. Sí, el patrón simple de doble verificación no es seguro. Pero puede hacerlo seguro declarando la instancia estática como volátil. La nueva especificación de Java Memory Model agrega algunas restricciones de código de reordenamiento para los compiladores cuando se trata de volátiles, por lo tanto, los riesgos originales se han ido.

De todos modos, rara vez realmente necesito este tipo de pereza cuando se crea la instancia, así que por lo general sólo tiene que crear estáticamente en el tiempo de la clase de carga:

private static MyClass instance = new MyClass(); 

Ésta es corto y claro.Como alternativa, si realmente quiere que sea perezoso, usted puede tomar ventaja de las características de carga de clase y hacer esto:

public class MyClass { 
    private static class MyClassInit { 
     public static final MyClass instance = new MyClass(); 
    } 

    public static MyClass getInstance() { 
     return MyClassInit.instance; 
    } 
... 
} 

La clase anidada no se cargará hasta que la primera vez que llame getInstance().