Sim, é necessário. Existem vários métodos que você pode usar para obter segurança de thread com inicialização lenta:
Sincronização Draconiana:
private static YourObject instance;
public static synchronized YourObject getInstance() {
if (instance == null) {
instance = new YourObject();
}
return instance;
}
Esta solução requer que cada thread seja sincronizado quando, na realidade, apenas os primeiros precisam ser.
Verifique a sincronização :
private static final Object lock = new Object();
private static volatile YourObject instance;
public static YourObject getInstance() {
YourObject r = instance;
if (r == null) {
synchronized (lock) { // While we were waiting for the lock, another
r = instance; // thread may have instantiated the object.
if (r == null) {
r = new YourObject();
instance = r;
}
}
}
return r;
}
Essa solução garante que apenas os primeiros poucos threads que tentarem adquirir seu singleton tenham que passar pelo processo de aquisição do bloqueio.
Inicialização sob demanda :
private static class InstanceHolder {
private static final YourObject instance = new YourObject();
}
public static YourObject getInstance() {
return InstanceHolder.instance;
}
Essa solução aproveita as garantias do modelo de memória Java sobre a inicialização de classe para garantir a segurança do thread. Cada classe só pode ser carregada uma vez e só será carregada quando for necessário. Isso significa que a primeira vez que getInstance
é chamada, InstanceHolder
será carregada e instance
criada, e como isso é controlado por ClassLoader
s, nenhuma sincronização adicional é necessária.
Draconian synchronization
eDouble check synchronization
getInstance () - o método deve ser estático!static
, mas faria mais sentido se fossem. Alterado conforme solicitado.r
não é necessário para correção. É apenas uma otimização para evitar o acesso ao campo volátil, já que é muito mais caro do que acessar uma variável local.Este padrão faz uma inicialização lenta segura com thread da instância sem sincronização explícita!
Funciona porque usa o carregador de classes para fazer toda a sincronização gratuitamente: a classe
MySingleton.Loader
é acessada primeiro dentro dogetInstance()
método, portanto, aLoader
classe é carregada quandogetInstance()
é chamada pela primeira vez. Além disso, o carregador de classes garante que toda a inicialização estática seja concluída antes de você obter acesso à classe - isso é o que oferece segurança de thread.É como mágica.
Na verdade, é muito semelhante ao padrão de enum de Jhurtado, mas acho o padrão de enum um abuso do conceito de enum (embora funcione)
fonte
final
deve ser adicionado. Feito.Se você está trabalhando em um ambiente multithread em Java e precisa garantir que todos esses threads acessem uma única instância de uma classe, você pode usar um Enum. Isso terá a vantagem adicional de ajudá-lo a lidar com a serialização.
e então faça com que seus threads usem sua instância como:
fonte
Sim, você precisa fazer
getInstance()
sincronizado. Se não for, pode surgir uma situação em que várias instâncias da classe podem ser feitas.Considere o caso em que você tem dois threads que chamam
getInstance()
ao mesmo tempo. Agora imagine que T1 é executado logo após ainstance == null
verificação e, em seguida, T2 é executado. Neste momento, a instância não foi criada ou configurada, então T2 passará na verificação e criará a instância. Agora imagine que a execução volte para T1. Agora o singleton está criado, mas T1 já fez a verificação! Ele continuará a fazer o objeto novamente! FazergetInstance()
sincronizado evita esse problema.Existem algumas maneiras de tornar os singletons thread-safe, mas fazer a
getInstance()
sincronização é provavelmente a mais simples.fonte
Enum singleton
A maneira mais simples de implementar um Singleton seguro para threads é usar um Enum
Este código funciona desde a introdução do Enum no Java 1.5
Bloqueio verificado duas vezes
Se você deseja codificar um singleton “clássico” que funciona em um ambiente multithread (a partir do Java 1.5), você deve usar este.
Isso não é seguro para thread antes de 1.5 porque a implementação da palavra-chave volatile era diferente.
Carregamento antecipado do Singleton (funciona mesmo antes do Java 1.5)
Essa implementação instancia o singleton quando a classe é carregada e fornece segurança de thread.
fonte
Você também pode usar o bloco de código estático para instanciar a instância no carregamento da classe e evitar os problemas de sincronização de encadeamento.
fonte
instance
2. Você deve fazergetInstance()
estático.Consulte esta postagem para obter a melhor maneira de implementar o Singleton.
Qual é uma maneira eficiente de implementar um padrão singleton em Java?
Depende da maneira como você implementou o método. Se você usar bloqueio duplo sem variável volátil, poderá obter o objeto Singleton parcialmente construído.
Consulte esta pergunta para obter mais detalhes:
Por que o volátil é usado neste exemplo de bloqueio com verificação dupla
Não é necessário se você implementar o Singleton das maneiras abaixo
Consulte esta questão para obter mais detalhes
Java Singleton Design Pattern: Perguntas
fonte
Fonte: Java Efetivo -> Item 2
Sugere usá-lo, se tiver certeza de que a classe sempre permanecerá solteira.
fonte