Propuesta de Singleton Pattern

Estimados compañeros:

Hace unas horas, estudiando el patrón de diseño OO Singleton, me surgió la siguiente idea para construir una propuesta del mismo, sin utilizar la clase anidada estática "Holder" y con esto simplificar el diseño, aunque creo que tiene sus desventajas.

Este constructo del Singleton está basado en la premisa de que una variable miembro estática es compartida por todas las instancias que la llamen, así que no encuentro ningún otro inconveniente más que la inicialización temprana de la clase y no bajo demanda. La clase también funciona en entorno multi-thread, aunque debo admitir que no he hecho pruebas muy exhaustivas donde ponga a prueba el rendimiento con la concurrencia de muchas clases.

Me gustaría que me dieran su opinión de este código, ya que soy relativamente nuevo en este tema y no he encontrado mucha ayuda en la red ni con mis amigos ya que no les gusta la programación.

Ya que estoy preparando el examen de Java Professional Certified de Oracle, su experiencia y sus comentarios serían de mucha utilidad para mi entrenamiento.

El código es el siguiente:

  1. public class Singleton {
  2.     public static Singleton instance = new Singleton();
  3.     private Singleton() { }
  4.     public Singleton getInstance() {
  5.          return instance;
  6.     }
  7.     public void metodoSingleton() {
  8.         System.out.println();
  9.     }
  10. }

El libro que estoy estudiando para el examen es "Oracle Certified Professional Java SE 7" de S G ganesh y Tushar Sharma :)

De antemano les doy las gracias por su atención y buenas noches!!!.

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de ElderMael

Observación

Suponiendo que yo corriera este pequeño ejemplo:

import org.junit.Test;

public class SingletonTestCase {

    @Test(expected = NullPointerException.class)
    public void instanceShouldBeTheSame() {

        // given
        final Singleton notSoSingleton = Singleton.instance;

        // when
        Singleton.instance = null;
        Singleton.instance.metodoSingleton();

        // then
        // Expect NPE

    }

}

Te das cuenta que no estás protegiendo tu singleton contra escritura? i.e. cualquiera podría hacer la referencia nula. Pero mas alla de los ejercicios y esas cosas: los singletons se consideran mayoritariamente una mala practica y hasta dañinos:

What is so bad about Singletons?

Imagen de marcosaw

Proteger el singleton contra escritura

Efectivamente, la clase ha quedado expuesta ya que la variable miembro "instance" la declaré pública, sin embargo, no me resulta del todo claro el por qué este patrón es mala práctica, aunque lo estudiaré con más calma. ¿Qué pasa entonces cuando quieres crear una instancia global para la aplicación? Por ejemplo un objeto que mantenga concentrado el logging de la api (con todas sus clases) en un único objeto. Supongo desde ahí que quizá haya otro patrón de diseño que solvente esta problemática. Por otro lado, quizá la solución para este ejemplo, aunque rudimentaria y gracias a tu comentario, podría ser:

  1. public class Singleton {
  2.     // instancia final y estática protegida contra escritura
  3.     // cualquier intento de cambiar esta referencia deriva en un error de compilación
  4.     private static final Singleton instance;
  5.     // se inicia de manera temprana
  6.     static {
  7.         instance = new Singleton();
  8.     }
  9.     private Singleton() {
  10.         // proteger la instancia directa con operador new
  11.     }
  12.     public void getInstance() {
  13.         return instance;
  14.     }
  15.     private metodo1() {
  16.         System.out.println("metodo 1");
  17.    }
  18. }

Quizá este ejemplo tenga protección contra escritura.

Por otro lado y gracias a tu comentario me pondré a investigar lo dañino que puede ser este patrón, aunque seguiré practicándolo ya que es parte de lo que te preguntan en el examen de certificación profesional en Oracle

Buenas noches

Imagen de ElderMael

¿Qué pasa entonces cuando


¿Qué pasa entonces cuando quieres crear una instancia global para la aplicación

Usas inyección de dependencias para proporcionar una sola instancia en sus dependencias.

El problema con el que más me encuentro usando un singleton por classloader es que una vez que haces una instancia estática (y como con todo lo estático) ya no puedes testear el código cliente sin testear la dependencia estática; a menos que uses librerías para hacer pruebas tapando el problema de fondo e.g. usar PowerMocks para hacerle un “mock” al método getInstance().

Siempre puedes hacerle refactoring a ese singleton pero también tienes que ponerte a pensar si es “thread-safe” y aparte la lógica necesaria si la instancia necesita configuraciones (tendrías que hacer que el propio objeto se configurara solo lo cual también es una bronca) e.g.:

 static {
        instance = new Singleton();
        configure(instance);
    }
Imagen de ElderMael

Logging

Por ejemplo un objeto que mantenga concentrado el logging de la api (con todas sus clases) en un único objeto.

Pues este es un code snippet muy usado con SLF4J:

protected static final Logger log = LoggerFactory
                        .getLogger(MyClass.class);

Aqui en realidad estas usando un factory para crear una instancia del logger que necesitas, que en todo caso no seria un singleton por classloader. Ya esta instancia viene configurada por el factory con lo necesario para hacer logging decente y maneja tambien una cadena de responsabilidad para los niveles; todo concentrado en este objeto y generalizando (abstrayendo) lo que mencionas.

Imagen de marcosaw

LoggerFactory y pruebas

En el caso de este framework slf4j entiendo que la fabrica produce una instancia del Logger de acuerdo al parámetro que se pasa al método getLogger(MyClass.class), que es el que le da el nombre interno al logger; aunque le puedes pasar cualquier cadena. Ahora, LoggerFactory está construida sobre el patrón Factory en combinación con una estrategia para crear una sola instancia del logger, si se provee el mismo parámetro (o la misma cadena de caracteres) al método getLogger. Derivado de esto mi pregunta es ¿Cómo se llama la estrategia usada en esta fábrica para crear una sola instancia del logger? y ¿Cómo enfrenta esta instancia un entorno multi-thread?

Concuerdo que la inyección de dependencias es lo más útil en los casos de requerir instancias únicas en el sistema, por lo que voy a explorar el tema, así como las alternativas que se ofrecen a este patrón de diseño. Sin embargo,me son muy útiles tus comentarios para ampliar mi conocimiento de este patrón, aunque más adelante evite usarlo en el mundo real, ya que es un tema que debo comprender muy bien para la certificación que estoy buscando en Oracle (1z0-804) y por lo que agradezco tu atención.

Con relación a las pruebas, he hecho lo básico con junit, aunque realmente no tengo tanta experiencia para comprender lo que me describes con relación a este tema, pero lo tomaré en cuenta en mis próximos ejercicios de pruebas unitarias y me pondré a leer más del tema.

Saludos y buenas noches

Singleton y enum

Otra solución interesante sería con enum:

public enum Singleton {

    INSTANCE;

    public void execute(String arg) {
        // perform operation here
    }

}

http://en.wikipedia.org/wiki/Singleton_pattern

Imagen de marcosaw

Ventajas con enum

En efecto, para asegurar una sola instancia, además naturalmente serializable, el tipo enum es la mejor opción. La única desventaja que he leído es que los tipos enum heredan implícitamente de java.lang.Enum, por lo que no pueden heredar de ninguna otra clase; aunque esto se soluciona con composición de clases o la implementación de interfaces, lo cual sí está permitido dentro de los enums. Sin duda el Singleton es un tema muy extenso y polémico como patrón de diseño, pero ¿Por qué es parte del examen iz0-804 de Oracle? Seguramente se usa de manera extendida en programas en el mundo real.

Imagen de ezamudio

eh?

"una sola instancia" y "serializable" son mutuamente excluyentes.

Imagen de marcosaw

mutuamente excluyentes

Derivado de tu comentario @ezamudio, hice una simple prueba con la opción del singleton con enum propuesta por @jpaul

Este es el código del enum:

  1. public enum EnumSingleton {
  2.     INSTANCE;
  3.    
  4.     private int id;
  5.    
  6.     public void doSometing() {
  7.         System.out.println("doSometing");
  8.         System.out.println("id de INSTANCE: " + id);
  9.     }
  10.    
  11.     public void setId(int id){
  12.         this.id = id;
  13.     }
  14. }

Este es el código del main

  1. import java.io.File;
  2. import java.io.FileInputStream;
  3. import java.io.FileOutputStream;
  4. import java.io.IOException;
  5. import java.io.ObjectInputStream;
  6. import java.io.ObjectOutputStream;
  7. import java.util.logging.Level;
  8. import java.util.logging.Logger;
  9.  
  10. public class TestEnumSingleton {
  11.  
  12.     public static void main(String[] args) {
  13.         File contenedor = new File("contenedor.cnt");
  14.         FileOutputStream fos = null;
  15.         ObjectOutputStream oos = null;
  16.        
  17.         FileInputStream fis = null;
  18.         FileInputStream fis2 = null;
  19.         ObjectInputStream ois = null;
  20.         ObjectInputStream ois2 = null;
  21.        
  22.         // escribo el singleton en el archivo anterior
  23.         try {
  24.             fos = new FileOutputStream(contenedor);
  25.             oos = new ObjectOutputStream(fos);
  26.             oos.writeObject(EnumSingleton.INSTANCE);
  27.         } catch (IOException e) {
  28.             e.printStackTrace();
  29.         }
  30.         finally {
  31.             try {
  32.                 if(oos != null) oos.close();
  33.                 if(fos != null) fos.close();
  34.                
  35.             } catch (IOException e) {
  36.                 e.printStackTrace();
  37.             }
  38.         }
  39.        
  40.         // lo llamo dos veces para checar si es un singleton
  41.         try {
  42.             fis = new FileInputStream(contenedor);
  43.             ois = new ObjectInputStream(fis);
  44.             // leo el primer objeto
  45.             EnumSingleton e1 = (EnumSingleton) ois.readObject();
  46.            
  47.             fis2 = new FileInputStream(contenedor);
  48.             ois2 = new ObjectInputStream(fis2);
  49.            
  50.             // leo el segundo objeto
  51.             EnumSingleton e2 = (EnumSingleton) ois2.readObject();
  52.            
  53.             // imprimo el identityHashCode de ambos y es el mismo
  54.             // ¿Hay otra manera de identificar si es la misma instancia o no?
  55.             System.out.println("hash e1: " + System.identityHashCode(e1));
  56.             System.out.println("hash e2: " + System.identityHashCode(e2));
  57.            
  58.             // seteo un id diferente para las referencias e1 y e2
  59.             e1.setId(1234);
  60.             e2.setId(6728);
  61.            
  62.             // invoco los métodos a las dos referencias que imprimen el id
  63.             // e imprime el último que hice el set
  64.             e1.doSometing(); // imprime 6728
  65.             e2.doSometing(); // imprime 6728
  66.            
  67.            
  68.         } catch (IOException e) {
  69.             e.printStackTrace();
  70.         } catch (ClassNotFoundException ex) {
  71.             Logger.getLogger(TestEnumSingleton.class.getName()).log(Level.SEVERE, null, ex);
  72.         }
  73.         finally{
  74.             try {
  75.                 if(ois != null) ois.close();
  76.                 if(fis != null) fis.close();
  77.                 if(ois2 != null) ois2.close();
  78.                 if(fis2 != null) fis2.close();
  79.             } catch (IOException e) {
  80.                 e.printStackTrace();
  81.             }
  82.         }
  83.     }
  84. }

Al parecer, al intentar hacer dos instancias del enum dos veces del archivo, sigue siendo la misma instancia. Quizá en otro tipo de prueba que desconozco, se puedan generar dos instancias de este enum, pero esta prueba me arroja la misma. Quizá debería probarla en dos máquinas virtuales distintas y, efectivamente, al serializar el enum se creará una instancia del mismo por cada máquina virtual que lo llame. Haré la prueba. Saludos y buenas noches.

Re: Observación

Claro que se consideran mala práctica cuando se usan de manera incorrecta. Hay muchos casos para los que funcionan, por ejemplo, la caché de un website, ¿es que vas a andar creando un objeto de caché por cada sesión o peor aún, por cada petición?.

Incluso en la pregunta de StackOverflow vienen unas consideraciones si te planteas utilizar singleton.

Y pues eso, dudo que sea una mala práctica o que sea dañino, creo que tienen su lugar y su razón de ser, depende que caso y resuelve un problema el cual es cuando un objeto necesita ser compartido entre varias instancias.

Re: mutuamente excluyentes

¿Pero que problema tiene la manera tradicional?

public class MySingleton{

  private static MySingleton instance = null;
  //properties declaration

  private MySingleton(){
    //initialize properties
  }

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

}

Imagen de marcosaw

La manera tradicional

El problema que he estudiado en el caso de un Singleton de la manera que lo planteas @wishmaster77, tiene que ver cuando utilizas MySingleton en un entorno Multi-hilo, por lo que hice esta prueba del libro con la misma clase que escribiste (MySingleton), la cual demuestra que se pueden crear varias instancias de esta clase, cuando no debería de ser posible, según el propósito de un singleton. También, en el caso de serializarla y realizar la prueba que hice con la versión "enum" del singleton, también puedes "transgredir" la propiedad de solo poder crear una sola instancia de esta clase para la aplicación.

Este es el código de prueba para la clase que propones (yo propuse una versión similar al principio de este post)

  1. package design_patterns.singleton2;
  2. public class TestSingletonMT implements Runnable{
  3.     // declaro una referencia de tipo MySingleton
  4.     private MySingleton ms = null;
  5.    
  6.     @Override
  7.     public void run() {
  8.         // en el método run inicializo la referencia "ms"
  9.         ms = MySingleton.getInstance();
  10.         try {
  11.             // dejo dormir el thread por medio segundo y en este momento
  12.             // es probable que se genere una segunda instancia de MySingleton
  13.             // en la llamada al métodolo cual es contrario al propósito de un
  14.             // Singleton
  15.             Thread.sleep((int)(Math.random() * 500));
  16.         } catch (InterruptedException e) {
  17.             throw new RuntimeException("Falla en el sleep");
  18.         }
  19.     }
  20.    
  21.     /**
  22.      * @return Retorna la instancia que se inicializó en el run() que,
  23.      * en la práctica debería ser la misma para todas las instancias de
  24.      * la clase TestSingletonMT
  25.      */
  26.     public MySingleton getMs() {
  27.         return ms;
  28.     }
  29.    
  30.     public static void main(String... args) {
  31.         // genero cinco instancias de TestSingletonMT
  32.         TestSingletonMT ts1 = new TestSingletonMT();
  33.         TestSingletonMT ts2 = new TestSingletonMT();
  34.         TestSingletonMT ts3 = new TestSingletonMT();
  35.         TestSingletonMT ts4 = new TestSingletonMT();
  36.         TestSingletonMT ts5 = new TestSingletonMT();
  37.        
  38.         // genero un Thread por cada instancia ts(n)
  39.         Thread t1 = new Thread(ts1);
  40.         Thread t2 = new Thread(ts2);
  41.         Thread t3 = new Thread(ts3);
  42.         Thread t4 = new Thread(ts4);
  43.         Thread t5 = new Thread(ts5);
  44.  
  45.         // start yeah!!!!        
  46.         t1.start();
  47.         t2.start();
  48.         t3.start();
  49.         t4.start();
  50.         t5.start();
  51.        
  52.         // de las cinco instancias de MySingleton recupero su instancia de
  53.         // MySingleton y la imprimo para ver si es la misma
  54.         System.out.println("MySingleton de ts1: " + ts1.getMs());
  55.         System.out.println("MySingleton de ts2: " + ts2.getMs());
  56.         System.out.println("MySingleton de ts3: " + ts3.getMs());
  57.         System.out.println("MySingleton de ts4: " + ts4.getMs());
  58.         System.out.println("MySingleton de ts5: " + ts5.getMs());
  59.        
  60.         // después de varias pruebas, hay ocasiones que me genera más de
  61.         // una instancia de MySingleton (hay pocas ocasiones que no)
  62.     }
  63. }

Realicé varias pruebas en las que se creó más de una instancia de MySingleton y algunas ocasiones me resultaban algunas referencias null (extraño jaja). Este fue el último resultado que obtuve:

  1. MySingleton de ts1: design_patterns.singleton2.MySingleton@5b181df3
  2. MySingleton de ts2: design_patterns.singleton2.MySingleton@c566b3e
  3. MySingleton de ts3: design_patterns.singleton2.MySingleton@7d9ab9c5
  4. MySingleton de ts4: design_patterns.singleton2.MySingleton@5b181df3
  5. MySingleton de ts5: design_patterns.singleton2.MySingleton@5b181df3

En las líneas dos y tres se crean otras dos instancias, como puedes ver. Por eso esta forma no es útil en un entorno multi-thread. Bueno, esa es la mejor explicación que encuentro jeje. Por otra parte, sigo pensando que los Singletons son útiles, y por algo los preguntan en el examen de certificación 1z0-804 de Oracle. Saludos y buenas tardes :)

Imagen de ElderMael

Como ya se comento, ese

Como ya se comento, ese codigo no es thread-safe.

Imagen de ElderMael

Claro que se consideran mala


Claro que se consideran mala práctica cuando se usan de manera incorrecta.

Pero... dime una manera correcta?

No es que no la haya pero pienso que si la hubiera podrías usar alternativas que probablemente serian mejor. En todo caso la única vez que probablemente he visto un uso del singleton (que en realidad me gusta mas como un null object o un flyweight) es en la clase Optional de Guava con el objeto Absent.

Re: La manera tradicional

En el caso de multi-hilos concuerdo con @ElderMael, se usa inyección de dependencias y te aseguras que la inyección se realice al iniciar la aplicación.

Re: Claro que se consideran mala

Lo dicho, depende para qué. Quizá a lo que estás acostumbrado Singleton sea una mala idea, quizá para alguien más sea algo tan válido.

Re: ¿Qué pasa entonces cuando

Pero si lo que preocupa realmente es hacer código thread-safe, creo que lo mejor sería aplicar algo más funcional, libre de estados.

Imagen de marcosaw

Singleton de estudio

Me queda claro que la inyección de dependencias es la opción para manipular la cantidad de instancias de una clase, ya que el contenedor de dependencias se encarga de gestionar esto, de acuerdo a la configuración del contenedor; esto es posible con clases que sean Singleton o no (da igual, pues la fábrica es quien controla esto, más no la propia clase). Sin embargo, el punto que planteo justo es profundizar en las ventajas y desventajas de este patrón, así como los pormenores que atraviesa su diseño para asegurar que una clase pueda ser instanciada una sola vez, con propósitos meramente estudiantiles enfocados al objetivo de pasar el examen 1zo-804, por lo que sus comentarios me han sido muy útiles ya que me han dado pautas para investigar y hacer más pruebas. De cualquier manera, en el ámbito laboral, como bien lo proponen, prefiero trabajar mis dependencias con Spring. Saludos y buenas noches.

Imagen de ezamudio

final

Regresando al ejemplo original, sólo le falta un final a la variable estática (para que no sea variable) y ya.

Re: final

Quedando:

public class MySingleton{
  private static final MySingleton instance = new MySingleton();
  //properties declaration

  private MySingleton(){
    //initialize properties
  }

  public static MySingleton getInstance(){
    return instance;
  }
}

También es una opción.

Imagen de marcosaw

static

Es la manera más cercana al Singleton, convertir en static fina a la referencia que contiene la instancia. Aún seguiré haciendo pruebas con el enum ya que me pareció interesante el tema de la serialización el tema de que Singleton y Serializable son mutuamente excluyentes. Lo haré con networking (rmi, socket) a ver cómo funciona, solo para saber qué es lo que pasa con el enum en este entorno, para posteriormente publicar los resultados. Muchas gracias por las aportaciones. Buenas noches a todos.

Re: static

Creo que deberías revisar esto que trata sobre el tema de serialización en enum con singleton. Es interesante.

Imagen de marcosaw

Lo voy a revisar

Por supuesto que lo revisaré wishmaster77 gracias.

Imagen de beto.bateria

Singleton thread-safe

Saludos a la banda:

Programo en moviles, y un problema comun es cuando el usuario accede a servicios por http, lo cual es usando threads, y como la red no es muy fiable que dijamos, entonces tenemos a un cliente oprimiendo el boton y la aplicacion consultando varias veces el servicio, si no usamos el singletos, se crearian varios procesos para acceder a internet, y en ocasiones el puerto del movil va a reclamar, diciendo que ya esta siendo usado, ademas de que la informacion no va a ser 100% fiable, debido que a la mejor se va a mostrar la informacion de varios procesos sin sincronizar.

Si usas un singleton normal, sera casi lo mismo, debido que, aunque usas una misma instancia, esta va a ser usada por varios procesos, en ocasiones simultaneamente, ¿Cual fue la solucion? agregarle synchronized a algunas partes del codigo, este ejemplo funciona de maravilla y evita muchos problemas:

public class Singleton {
       
        private static Singleton instance = null;
   
    private Singleton() {}
   
    public void setConfiguration(Action action, Controllable controller, HttpConfigurator httpConfigurator){
        this.action = action;
        this.controller = controller;
        this.httpConfigurator = httpConfigurator;
    }
   
    public synchronized void execute() throws ParserConfigurationException, SAXException, IOException{

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

Imagen de marcosaw

Interesante triple check

Interesante hacer ese triple check sincronizado en la app, pero ¿No genera problemas de rendimiento? ¿No es suficiente con hacer final la referencia "instance"?, voy a realizar pruebas con threads a ver cómo funciona este triple check. Gracias.

Imagen de ElderMael

Queue

[...]si no usamos el singletos [sic], se crearian varios procesos para acceder a internet[...]

También podrías haber usado un BlockingQueue con capacidad 0 en donde los hilos esperaran a ser despachados (con o sin un ExecutorService) y basicamente tendrias el mismo resultado. O si no deseas que los threads esperen entonces igual y cancelas el task actual o le darias mas capacidad. Como un event queue de los que usan a veces en Ruby.

Imagen de ezamudio

doble

Con doble synchronized es suficiente. El synchronized a nivel metodo en getInstance sobra, de hecho hace que el codigo sea muy ineficiente puesto que siempre SIEMPRE se hace un bloqueo al invocar el metodo. La idea de tener el doble synchronized internamente es que solamente ocurren esos bloqueos cuando se crea la instancia compartida y despues ya no se ejecutan.

La diferencia entre esto y tener la instancia en un campo final, es que con este enfoque se crea la instancia unicamente cuando alguien la pide. Si en la vida de la aplicacion nadie la requiere, no se crea nunca. Con el campo final se crea el singleton cuando se carga esa clase.

Imagen de marcosaw

synchronized a nivel de método

Coincido con ezamudio, creo que el synchronized en la declaración del método hace más lenta la aplicación, ya que bloquea el método todas las veces que se invoca de manera concurrente. Con los bloques sincronizados dentro del método solo se bloquea una vez cuando la instancia se crea, ya que las demás veces los instance == null evaluan a false y el flujo de la ejecución ya no entra a los bloques sincronizados.

Digamos que quedaría así beto.bateria, con solo el doble check

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

De esta manera se obtiene el mejor performance del método

Por otro lado creo que la interface BlockingQueue tengo que estudiarla en el próximo capítulo de mi curso que se trata de threads y concurrencia.Ya estaré comentando como me fue en ese punto, porque en genéricos y colecciones no está ese tema.

Saludos a todos

Pues de que tanto hablan en

Pues de que tanto hablan en este post?

Sobre el ejemplo inicial ademas de que se puede cambiar la referencia al no ser final otro problema que crea al ser público es que crea mayor acoplamiento entre la clase y sus clientes.

La idea era hacer algo mas sencillo que el metodo "holder" pero al final parece que esta resultando mas complejo. El metodo holder es especialmente efectivo en Java por la forma en la que funciona el classloader. No aplica para otros lenguajes.

Entonces, si no importa que se cargue prematuramente esta implementación funciona bien:

public final class Singleton {
    private final static Singleton INSTANCE = new Singleton();
    private Singleton() {
         ... // inicializacion aqui
    }
    public static Singleton getInstance() {
        return INSTANCE;
    }
    public void methodOne() { ... }
}

Y si se necesita inicializacion tardía el metodo holder es:

public final class Sigleton {
    private Singleton() {
         ... // inicializacion aqui
    }
    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
    public void methodOne() { ... }
    private static class Holder {
       private final static Singleton INSTANCE = new Singleton();
    }
}

Ambos son thread-safe.

Nota aparte ( y pedante ): En Java no existen métodos o atributos estáticos como en C, se llaman de: "de clase" ( atributo / variable de clase, metodo de clase ).

Imagen de julgo

doble??

me parece que el doble synchronized tampoco es necesario ya que el candado para la clase esta tomado por el primero y el segundo al estar dentro del bloque solo hace repetirlo

//se sincroniza la clase
synchronized(Singleton.class){
             Singleton inst = instance;
             if (inst == null){
//ya estaba sincronizada la clase singleton
                 synchronized(Singleton.class){
                     instance = new Singleton();              
                 }
             }
         }
Imagen de ezamudio

no es necesario

No, no es necesario doble synchronized. Lo que sí es necesario es doble verificación de null:

if (instance == null) {
  synchronized(Singleton.class) {
    if (instance == null) {
      instance = new Singleton();
    }
  }
}

La verificacion dentro del bloque synchronized es porque mientras no existe el singleton, pueden llegar varios hilos al primer if y se les cumple la condicion.

Imagen de marcosaw

Métodos estáticos

Bien, este post justamente lo propuse para mejorar mi entrenamiento para el 1z0-804 con la opinión de personas experimentadas, que hay muchas en este foro. Las respuestas que he recibido conforme al patrón mismo, como los que no recomiendan usarlo, me han servido para mirar desde diferentes perspectivas el objeto de estudio y, con eso mejorar la percepción que tengo del patrón, su uso y las ventajas y/o desventajas que tiene usarlo en un entorno real. Es por eso que se ha vuelto complejo pero, sin embargo útil para el propósito del post.

Por otro lado, difiero de la afirmación que haces @OscarRyz diciendo que en java no existen los métodos estáticos. Te comento que no conozco otro lenguaje de programación más que este, y en todos (absolutamente todos) los materiales de estudio que utilicé para el examen de certificación 1z0-803 (en inglés la mayoría) incluyendo las publicaciones de Oracle y el mismo examen para tal efecto, mencionan textualmente "static method" para referirse a estos métodos, y en pocas ocasiones los mencionan como "class method", pero afirmo que usan indistintamente ambos términos, y ante eso (no sé cómo sea en otros lenguajes), es correcto llamarlos métodos estáticos o métodos de clase.

Finalmente y con algunas pruebas pendientes, creo que el libro que tengo se queda corto en la explicación del singleton, ya que aquí han surgido diversas versiones de las cuales me quedaría para efectos prácticos con 4 modelos:

Carga temprana de la instancia

public final class Singleton {
    private final static Singleton INSTANCE = new Singleton();
    private Singleton() {
         ... // inicializacion aqui
    }
    public static Singleton getInstance() {
        return INSTANCE;
    }
    public void methodOne() { ... }
}

Carga por demanda de la instancia

public final class Sigleton {
    private Singleton() {
         ... // inicializacion aqui
    }
    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
    public void methodOne() { ... }
    private static class Holder {
       private final static Singleton INSTANCE = new Singleton();
    }
}

Doble check

public static Singleton getInstance(){
    if (instance == null){
        synchronized(Singleton.class){
            Singleton inst = instance;
            if (inst == null){
                // synchronized(Singleton.class){ modificado este bloque por las respuestas de @julgo y @ezamudio
                    instance = new Singleton();              
                // }
            }
        }
    }
    return instance;
}

Enum Singleton

public enum Singleton {
    INSTANCE;
    public void execute(String arg) {
        // perform operation here
    }
}

Por lo visto y las diferentes fuentes de estudio, estos son los que más se mencionan, y qué mejor que estudiarlos y probarlos con detenimiento para un mejor aprendizaje ¿No lo creen?.

Saludos a todos y buenas noches.

Re: Pues de que tanto hablan en

Nota aparte ( y pedante ): En Java no existen métodos o atributos estáticos como en C, se llaman de: "de clase" ( atributo / variable de clase, metodo de clase ).

Se puede decir más alto pero no más claro ;)

Imagen de bferro

Un buen artículo sobre Double-Checked Locking Pattern

Este artículo es ya viejo. Vale la pena digerirlo. Aunque se discute en el ámbito de C++, lo que contiene aplica en general para Java.
C++ and The Perils of Double-Checked Locking: Part I
C++ and The Perils of Double-Checked Locking: Part II<

Imagen de marcosaw

Voy por C++

Sin duda un artículo interesante pero creo que necesito aprender C++ para entenderlo a profundidad. Lo que me queda claro es que todo tiene su complejidad por simple que parezca. Al respecto ya había leído en un libro que el double check puede (o podía) fallar en la JVM, de acuerdo a un bug con referencia al manejo de la memoria (creo que ya se solucionó), por lo que la opción más segura que he encontrado, en un Sigleton de carga de clase diferida, creo que la mejor opción es la que contiene la clase anidada Holder, ya que carga la instancia hasta que esta es requerida y no contiene métodos sincronizados. Buena tarde a todos.

Imagen de ezamudio

cerrando

En fin desde hace tiempo quería cerrar este tema porque es duplicado de este otro, que además ya está resuelto también:

http://www.javamexico.org/blogs/hackchan/forma_correcta_singleton#commen...