Executando verificação de segurança...
1

Bom post, mas acho que vale complementar com alguns detalhes.

A implementação sugerida não é thread-safe, ou seja, se várias threads chamarem Singleton.getInstance(), pode ser que ele crie mais de uma instância. Modifiquei um pouco o seu exemplo para ilustrar melhor:

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

    public static Singleton getInstance() {
        if (instance == null) { // adicionando uns prints pra saber quando cria uma instância
            System.out.println("criando nova instancia: ");
            instance = new Singleton();
            System.out.println("nova instancia criada: " + instance);
        }
        return instance;
    }
}

E testando com várias threads:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class Teste {
    public static void main(String[] args) throws Exception {
        List<Callable<Singleton>> tasks = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            tasks.add(() -> Singleton.getInstance());
        }
        ExecutorService executor = Executors.newFixedThreadPool(10);
        for (Future<Singleton> result : executor.invokeAll(tasks)) {
            System.out.println(result.get());
        }
        executor.awaitTermination(3, TimeUnit.SECONDS);
        executor.shutdown();
    }
}

Ou seja, crio 10 threads, e todas elas chamam Singleton.getInstance(). No final eu percorro os resultados e vejo qual instância foi retornada. O resultado foi:

criando nova instancia: 
criando nova instancia: 
criando nova instancia: 
nova instancia criada: Singleton@47a2a66c
nova instancia criada: Singleton@6f9777db
nova instancia criada: Singleton@1dc022f6
Singleton@47a2a66c
Singleton@47a2a66c
Singleton@47a2a66c
Singleton@6f9777db
Singleton@47a2a66c
Singleton@47a2a66c
Singleton@47a2a66c
Singleton@47a2a66c
Singleton@47a2a66c
Singleton@47a2a66c

No caso, foram criadas 3 instâncias. Claro que isso pode variar a cada execução, já que threads não são determinísticas, mas enfim, se precisar de um singleton em um ambiente multi-thread, aí tem que mudar um pouco a abordagem.


Alternativa thread-safe

Uma forma de resolver é usar a técnica chamada Initialization-on-demand holder, explicada em detalhes aqui. Ficaria assim:

public final class Singleton {
    private Singleton() {
        System.out.println("criando novo singleton"); // apenas para fins de debug
    }

    private static class Holder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}

Agora rodando o mesmo código que roda as 10 threads, o resultado é:

criando novo singleton
Singleton@7ba4f24f
Singleton@7ba4f24f
Singleton@7ba4f24f
Singleton@7ba4f24f
Singleton@7ba4f24f
Singleton@7ba4f24f
Singleton@7ba4f24f
Singleton@7ba4f24f
Singleton@7ba4f24f
Singleton@7ba4f24f

Ou seja, apenas uma instância é criada. Basicamente, isso é garantido pela forma como o class loader trabalha. A explicação abaixo foi retirada do link já citado:

  • o class loader carrega as classes assim que elas são acessadas (neste caso, o único acesso a Holder é dentro do método getInstance())
  • quando uma classe é carregada, e antes que qualquer um a use, é garantido que todos os inicializadores estáticos são executados (é aí que o campo Holder.INSTANCE é inicializado)
  • o class loader tem seus próprios mecanismos de sincronização, que garantem que o código acima é thread safe

Indo um pouco mais além, vale lembrar que um singleton é único por JVM. Ou seja, se seu ambiente roda em um cluster, cada nó do cluster terá uma instância. Se quer garantir unicidade entre os clusters, aí precisa de outras técnicas específicas, e varia muito caso a caso (depende do servidor de aplicação, do que exatamente vc está fazendo com o singleton, etc).

1

Uaaaaalllll kht que top demais !!!

Muito obrigado primeiro pelo conhecimento compartilhado e aprendizado (aprendi mais uma hj), segundo segundo pelo complemento ao post, valeu demais ^^.