Galera,
Acho que não precisa de código sincronizado, senão vejamos:
class MySingleton {
private static MySingleton me = new MySingleton();
private MySingleton() {}
public static MySingleton getInstance() {return me;}
}
class TestSingleton {
static MySingleton s1 = MySingleton.getInstance();
static MySingleton s2 = MySingleton.getInstance();
public static void main(String[] args) {
System.out.println("So tenho UMA instancia do Singleton? " + (s1 == s2));
}
A saída produz o resultado desejado: true. Ao mesmo tempo esse código é thread-safe, pois a variável de classe "me" é inicializada durante o carregamento da classe, antes de qualquer thread executá-la. Mas, fica a dúvida: seria possível ter MAIS DE UMA INSTÂNCIA DO MESMO SINGLETON? Bem, se vc usar a classe de forma normal a coisa funciona bem. Mas, é possível sim ter mais de uma instância. Veja como:
import java.net.*;
import java.lang.reflect.*;
public class TestSingleton {
public static void main(String [] args) throws Exception {
URL url = new URL("file:subdir/");
URL[] urls = new URL[]{url};
URLClassLoader loader1 = new URLClassLoader(urls);
URLClassLoader loader2 = new URLClassLoader(urls);
// carregamos a classe na mão...
Class cls1 = loader1.loadClass("MySingleton");
Class cls2 = loader2.loadClass("MySingleton");
// instanciamos agora os dois Singletons por invocacao reflexiva
Method m1 = cls1.getMethod("getInstance", null);
Object o1 = m1.invoke(null, null);
Method m2 = cls2.getMethod("getInstance", null);
Object o2 = m2.invoke(null, null);
//Comprovando que temos dois Singletons diferentes
System.out.println("Singleton 1:" + o1);
System.out.println("Singleton 2:" + o2);
}
}
Saída:
Singleton 1:MySingleton@a18aa2
Singleton 2:MySingleton@194ca6c
Uma vez que temos duas instâncias de Singleton, podemos invocar qualquer um de seus métodos de forma reflexiva. Infelizmente não conheço nenhuma forma de evitar isso. Talvez seja possível evitar isso usando SecurityManager.
Até a próxima... :)