Bloqueio verificado duas vezes. Em geral.
O paradigma, no qual comecei a aprender os problemas de quando estava trabalhando na BEA, é que as pessoas verifiquem um singleton da seguinte maneira:
public Class MySingleton {
private static MySingleton s_instance;
public static MySingleton getInstance() {
if(s_instance == null) {
synchronized(MySingleton.class) { s_instance = new MySingleton(); }
}
return s_instance;
}
}
Isso nunca funciona, porque outro encadeamento pode ter entrado no bloco sincronizado e s_instance não é mais nulo. Portanto, a mudança natural é:
public static MySingleton getInstance() {
if(s_instance == null) {
synchronized(MySingleton.class) {
if(s_instance == null) s_instance = new MySingleton();
}
}
return s_instance;
}
Isso também não funciona, porque o Java Memory Model não é compatível. Você precisa declarar s_instance como volátil para fazê-lo funcionar e, mesmo assim, ele funciona apenas no Java 5.
Pessoas que não estão familiarizadas com os meandros do Java Memory Model mexem nisso o tempo todo .