Pergunta

O que é uma maneira eficiente de implementar um padrão singleton em Java?

Foi útil?

Solução

Use um enum:

public enum Foo {
    INSTANCE;
}

Joshua Bloch explicou essa abordagem em seu Eficaz Java Reloaded falar em Google I/O de 2008: link do vídeo.Veja também os slides 30-32 de sua apresentação (effective_java_reloaded.pdf):

O Caminho Certo para Implementar Serializable Singleton

public enum Elvis {
    INSTANCE;
    private final String[] favoriteSongs =
        { "Hound Dog", "Heartbreak Hotel" };
    public void printFavorites() {
        System.out.println(Arrays.toString(favoriteSongs));
    }
}

Editar: Um parte on-line "Effective Java" diz:

"Essa abordagem é funcionalmente equivalente para o público de campo de abordagem, exceto que ele é mais conciso, fornece a serialização de máquinas para livre, e oferece a garantia de qualidade em relação a várias instâncias, mesmo em face de uma sofisticada de serialização ou ataques de reflexão.Embora essa abordagem ainda tem de ser amplamente adotada, um único elemento do tipo enum é a melhor maneira de implementar um singleton."

Outras dicas

Dependendo do uso, há várias respostas "corretas".

Desde java5 a melhor maneira de fazer isso é usar um enum:

public enum Foo {
   INSTANCE;
}

Pré java5, o mais simples caso é:

public final class Foo {

    private static final Foo INSTANCE = new Foo();

    private Foo() {
        if (INSTANCE != null) {
            throw new IllegalStateException("Already instantiated");
        }
    }

    public static Foo getInstance() {
        return INSTANCE;
    }

    public Object clone() throws CloneNotSupportedException{
        throw new CloneNotSupportedException("Cannot clone instance of this class");
    }
}

Vamos fazer o código.Primeiro, você deseja que a classe a ser definitiva.Neste caso, eu usei o final palavra-chave para permitir que os usuários sabem que é final.Em seguida, você precisa fazer o construtor privado para impedir que os usuários criem seus próprios Foo.Lançar uma exceção do construtor impede que os usuários para usar a reflexão para criar uma segunda Foo.Em seguida, você criar uma private static final Foo campo para armazenar a única instância, e um public static Foo getInstance() método para retornar a ele.A especificação do Java certifica-se de que o construtor é chamado apenas quando a classe é usada pela primeira vez.

Quando você tiver um grande objeto ou construção pesada de código E também tem outros acessível métodos estáticos ou campos que podem ser usados antes de uma instância é necessária, então, e somente então, você precisa usar a inicialização lenta.

Você pode usar um private static class para carregar a instância.O código seria parecido com:

public final class Foo {

    private static class FooLoader {
        private static final Foo INSTANCE = new Foo();
    }

    private Foo() {
        if (FooLoader.INSTANCE != null) {
            throw new IllegalStateException("Already instantiated");
        }
    }

    public static Foo getInstance() {
        return FooLoader.INSTANCE;
    }
}

Desde a linha private static final Foo INSTANCE = new Foo(); só é executado quando a classe FooLoader é realmente utilizado, este encarrega-se da preguiça instanciação, e é garantido de ser thread-safe.

Quando você deseja também ser capaz de serializar o objeto que você precisa para se certificar de que a desserialização não criar uma cópia.

public final class Foo implements Serializable {

    private static final long serialVersionUID = 1L;

    private static class FooLoader {
        private static final Foo INSTANCE = new Foo();
    }

    private Foo() {
        if (FooLoader.INSTANCE != null) {
            throw new IllegalStateException("Already instantiated");
        }
    }

    public static Foo getInstance() {
        return FooLoader.INSTANCE;
    }

    @SuppressWarnings("unused")
    private Foo readResolve() {
        return FooLoader.INSTANCE;
    }
}

O método readResolve() vai certifique-se de que a instância só será devolvido, mesmo quando o objeto foi serializado em uma execução anterior do seu programa.

Isenção de responsabilidade: Eu tenho apenas resumiu todos os fantásticos respostas e escreveu-o em minhas palavras.


Enquanto a implementação de Singleton temos 2 opções
1.Carregamento lento
2.Início de carregamento

Carregamento lento adiciona bits de overhead(muitos para ser honesto) para usá-lo somente quando você tiver um grande objeto ou construção pesada de código E também tem outros acessível métodos estáticos ou campos que podem ser usados antes de uma instância é necessária, então, e somente então, você precisa usar a inicialização lenta.Caso contrário, a escolha de carregamento inicial é uma boa escolha.

Forma mais simples de implementação de Singleton é

public class Foo {

    // It will be our sole hero
    private static final Foo INSTANCE = new Foo();

    private Foo() {
        if (INSTANCE != null) {
            // SHOUT
            throw new IllegalStateException("Already instantiated");
        }
    }

    public static Foo getInstance() {
        return INSTANCE;
    }
}

Tudo o que é bom, exceto o seu início carregado singleton.Vamos tentar lenta carregado singleton

class Foo {

    // Our now_null_but_going_to_be sole hero 
    private static Foo INSTANCE = null;

    private Foo() {
        if (INSTANCE != null) {
            // SHOUT  
            throw new IllegalStateException("Already instantiated");
        }
    }

    public static Foo getInstance() {
        // Creating only  when required.
        if (INSTANCE == null) {
            INSTANCE = new Foo();
        }
        return INSTANCE;
    }
}

Até aí tudo bem, mas o nosso herói não vai sobreviver enquanto luta sozinho com vários mal segmentos que querem muitos, muitos instância do nosso herói.Então vamos protegê-lo do mal multi-threading

class Foo {

    private static Foo INSTANCE = null;

    // TODO Add private shouting constructor

    public static Foo getInstance() {
        // No more tension of threads
        synchronized (Foo.class) {
            if (INSTANCE == null) {
                INSTANCE = new Foo();
            }
        }
        return INSTANCE;
    }
}

mas não é o suficiente para proteger as herói, Realmente!!!Este é o melhor que pode/deve fazer para ajudar o nosso herói

class Foo {

    // Pay attention to volatile
    private static volatile Foo INSTANCE = null;

    // TODO Add private shouting constructor

    public static Foo getInstance() {
        if (INSTANCE == null) { // Check 1
            synchronized (Foo.class) {
                if (INSTANCE == null) { // Check 2
                    INSTANCE = new Foo();
                }
            }
        }
        return INSTANCE;
    }
}

Isso é chamado de "Double-Checked Locking expressão idiomática".É fácil esquecer o voláteis instrução e difícil de entender por que é necessário.
Para mais detalhes : http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

Agora temos a certeza sobre o mal thread, mas o que sobre o cruel serialização?Temos que ter a certeza mesmo, enquanto a de-serialiaztion nenhum novo objeto é criado

class Foo implements Serializable {

    private static final long serialVersionUID = 1L;

    private static volatile Foo INSTANCE = null;

    // Rest of the things are same as above

    // No more fear of serialization
    @SuppressWarnings("unused")
    private Object readResolve() {
        return INSTANCE;
    }
}

O método readResolve() vai certifique-se de que a instância só será devolvido, mesmo quando o objeto foi serializado em uma execução anterior do nosso programa.

Finalmente, nós adicionamos proteção suficiente contra threads de serialização, mas o nosso código está procurando volumosos e feio.Vamos dar o nosso herói um fazer mais

public final class Foo implements Serializable {

    private static final long serialVersionUID = 1L;

    // Wrapped in a inner static class so that loaded only when required
    private static class FooLoader {

        // And no more fear of threads
        private static final Foo INSTANCE = new Foo();
    }

    // TODO add private shouting construcor

    public static Foo getInstance() {
        return FooLoader.INSTANCE;
    }

    // Damn you serialization
    @SuppressWarnings("unused")
    private Foo readResolve() {
        return FooLoader.INSTANCE;
    }
}

Sim, este é o nosso muito mesmo herói :)
Desde a linha private static final Foo INSTANCE = new Foo(); só é executado quando a classe FooLoader na verdade, é usado, este encarrega-se da preguiça instanciação,

e é garantido que seja thread-safe.

E temos que veio até agora, aqui está a melhor maneira de conseguir tudo o que fizemos é melhor maneira possível

 public enum Foo {
       INSTANCE;
   }

Que internamente será tratada como

public class Foo {

    // It will be our sole hero
    private static final Foo INSTANCE = new Foo();
}

Que de ti não há mais medo de serialização, threads e feio código.Também ENUMS singleton são inicializados de forma preguiçosa.

Esta abordagem é funcionalmente equivalente para o público de campo de abordagem, exceto que ele é mais conciso, fornece a serialização de máquinas de graça, e oferece a garantia de qualidade em relação a vários instanciação, mesmo em face de uma sofisticada de serialização ou ataques de reflexão.Embora essa abordagem ainda tem de ser amplamente adotada, um único elemento do tipo enum é a melhor maneira de implementar um singleton.

-Joshua Bloch em "Effective Java"

Agora você pode ter percebido por que as ENUMERAÇÕES são considerados como a melhor forma de implementar Singleton e obrigado pela paciência :)
Atualizado em meu blog.

A solução postado por Sérgio Thompson é válido em Java5.0 e posterior.Mas eu prefiro não usá-lo porque eu acho que é passível de erro.

É fácil esquecer o voláteis instrução e difícil de entender por que é necessário.Sem o voláteis este código não seria segmento mais seguro devido ao duplo-verificada fecho antipattern.Veja mais sobre isto no parágrafo 16.2.4 de Java Simultaneidade na Prática.Em resumo:Este padrão (antes de Java5.0 ou sem o voláteis instrução) pode retornar uma referência ao objeto de Barra que (ainda) é um estado incorreto.

Este padrão foi inventado para a otimização de desempenho.Mas isso realmente não é uma preocupação real com a mais.O seguinte preguiçoso código de inicialização é rápida e ainda mais importante, de mais fácil leitura.

class Bar {
    private static class BarHolder {
        public static Bar bar = new Bar();
    }

    public static Bar getBar() {
        return BarHolder.bar;
    }
}

O Thread de segurança no Java 5+:

class Foo {
    private static volatile Bar bar = null;
    public static Bar getBar() {
        if (bar == null) {
            synchronized(Foo.class) {
                if (bar == null)
                    bar = new Bar(); 
            }
        }
        return bar;
    }
}

EDITAR:Preste atenção ao volatile modificador aqui.:) É importante porque sem ele, outros threads não são garantidos pelo JMM (Modelo de Memória Java) para ver as alterações para o seu valor.A sincronização não cuidar do que é apenas serializa acesso ao bloco de código.

EDIT 2:@Bno 's respostas detalhes a abordagem recomendada por Bill Pugh (FindBugs) e é possível argumentar melhor.Vá ler e votar a sua resposta também.

Esqueça a inicialização lenta, é muito problemático.Esta é a solução mais simples:

public class A {    

    private static final A INSTANCE = new A();

    private A() {}

    public static A getInstance() {
        return INSTANCE;
    }
}

Certifique-se de que você realmente precisa.Fazer um google por "singleton anti-pattern" para ver alguns argumentos contra ela.Não há nada de errado com ele, eu suponho, mas é apenas um mecanismo para expor alguns global de recursos/dados de modo a certificar-se de que esta é a melhor maneira.Em particular, eu encontrei a injeção de dependência mais útil particularmente se você também estiver usando testes de unidade, porque DI permite que você use zombaram de recursos para fins de teste.

Eu estou iludido por algumas das respostas que sugerem que o DI como uma alternativa ao uso de gestações únicas;estes estão relacionados com os conceitos.Você pode usar o DI para injetar um singleton ou non-singleton (e.g.por thread) instâncias.Pelo menos isso é verdadeiro se você usar Primavera 2.x, eu não posso falar por outros quadros de DI.

Portanto, a minha resposta para o OP seria (em todos, mas as mais triviais de código de exemplo) para:

  1. Usar um DI framework como o Spring, em seguida,
  2. Torná-lo parte de seu DI configuração se o seu dependências são singletons, pedido de escopo, sessão de escopo, ou seja o que for.

Esta abordagem dá-lhe uma boa dissociado (e, portanto, flexível e testável) de arquitetura, onde se usa um singleton é facilmente reversível detalhe de implementação (desde que qualquer singletons você usa são thread-safe, é claro).

Realmente considerar o qual você precisa de um singleton antes de escrever.Há uma quase-religiosa debate sobre o uso deles que você pode facilmente tropeçar se você procurar no google gestações únicas em Java.

Pessoalmente, eu tento evitar gestações únicas, tão frequentemente quanto possível, por muitas razões, novamente, a maioria dos quais pode ser encontrado por googling gestações únicas.Eu sinto que, muitas vezes singletons são abusadas porque elas são fáceis de entender por todos, eles são usados como um mecanismo para a obtenção de "global" de dados em um design OO e eles são usados porque ele é fácil de contornar objeto de gerenciamento do ciclo de vida (ou realmente pensar sobre como você pode fazer Um a partir de dentro B).Olhar para as coisas como Inversão de Controle (IoC) ou Injeção de Dependência (DI) para um bom middleground.

Se você realmente precisa de um, em seguida, a wikipedia tem um bom exemplo de uma boa implementação de um singleton.

A seguir são 3 diferentes abordagens

1) Enum

/**
* Singleton pattern example using Java Enumj
*/
public enum EasySingleton{
    INSTANCE;
}

2) verificado duas vezes Fecho /carregamento lento

/**
* Singleton pattern example with Double checked Locking
*/
public class DoubleCheckedLockingSingleton{
     private static volatile DoubleCheckedLockingSingleton INSTANCE;

     private DoubleCheckedLockingSingleton(){}

     public static DoubleCheckedLockingSingleton getInstance(){
         if(INSTANCE == null){
            synchronized(DoubleCheckedLockingSingleton.class){
                //double checking Singleton instance
                if(INSTANCE == null){
                    INSTANCE = new DoubleCheckedLockingSingleton();
                }
            }
         }
         return INSTANCE;
     }
}

3) Estática método de fábrica

/**
* Singleton pattern example with static factory method
*/

public class Singleton{
    //initailzed during class loading
    private static final Singleton INSTANCE = new Singleton();

    //to prevent creating another instance of Singleton
    private Singleton(){}

    public static Singleton getSingleton(){
        return INSTANCE;
    }
}

Eu uso o Spring Framework para gerenciar minhas gestações únicas.Não aplicar a "singleton-ness" da classe (que você não pode realmente fazer qualquer maneira, se existem várias classes de carregadores envolvidos), mas que oferece uma maneira muito fácil para criar e configurar diferentes fábricas para a criação de diferentes tipos de objetos.

Versão 1:

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

Carregamento lento de thread segura, com o bloqueio, o baixo desempenho devido a synchronized.

Versão 2:

public class MySingleton {
    private MySingleton() {}
    private static class MySingletonHolder {
        public final static MySingleton instance = new MySingleton();
    }
    public static MySingleton getInstance() {
        return MySingletonHolder.instance;
    }
}

Carregamento lento, o thread de segurança com bloqueio não, de alto desempenho.

A wikipédia tem alguns exemplos de singletons, também em Java.O Java 5 implementação parece bastante completa, e é thread-safe (double-checked locking aplicadas).

Se você não precisa de carregamento lento em seguida, basta tentar

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

    private Singleton() {}

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

    protected Object clone() {
        throw new CloneNotSupportedException();
    }
}

Se você deseja carregamento lento e você deseja que sua Singleton ser thread-safe, tente o duplo padrão de verificação de

public class Singleton {
        private static Singleton instance = null;

        private Singleton() {}

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

        protected Object clone() {
            throw new CloneNotSupportedException();
        }
}

Como o duplo padrão de verificação não é garantido que funcione (devido a algum problema com compiladores, eu não sei nada mais sobre isso.), você também pode tentar sincronizar todo o getInstance-método ou criar um registro para todas as suas gestações únicas.

Eu diria Enum singleton

Singleton usando enum em Java é geralmente a forma de declarar enum singleton.Enum singleton pode conter variável de instância e de instância de método.Para fins de simplicidade, observe também que se você estiver usando qualquer método de instância que você precisa para garantir a segurança do thread de que o método se a tudo o que afeta o estado do objeto.

O uso de um enum é muito fácil de implementar e não tem desvantagens em relação serializable objetos, que devem ser evitadas em outras formas.

/**
* Singleton pattern example using Java Enum
*/
public enum Singleton {
        INSTANCE;
        public void execute (String arg) {
                //perform operation here
        }
}

Você pode acessá-lo por Singleton.INSTANCE, muito mais fácil do que chamar getInstance() método Singleton.

1.12 Serialização de Constantes Enum

Enum constantes são serializados de forma diferente da ordinária serializable ou externalizable objetos.O serializado forma de uma enumeração constante consiste unicamente de seu nome;campo de valores da constante não estão presentes no formulário.Para serializar um enum constante, ObjectOutputStream escreve o valor retornado pela enumeração constante do nome do método.Anular a serialização de um enum constante, ObjectInputStream lê-se o nome de constante de fluxo;desserializado constante é, então, obtido chamando o java.lang.Enum.valueOf o método, passando a constante do tipo enum, juntamente com o recebeu o nome de constante como argumentos.Como outros serializable ou externalizable objetos, constantes enum pode funcionar como destinos de volta referências que aparecem posteriormente na serialização de fluxo.

O processo pelo qual constantes enum são serializados não podem ser personalizadas:qualquer classe específico writeObject, readObject, readObjectNoData, writeReplace, e readResolve métodos definidos por tipos de enum são ignorados durante a serialização e desserialização.Da mesma forma, qualquer serialPersistentFields ou serialVersionUID campo declarações também são ignoradas--todos os tipos de enum fixo serialVersionUID de 0L.Documentar serializable e campos de dados para tipos de enum é desnecessária, uma vez que não há variação no tipo de dados enviados.

Citado a partir da Oracle docs

Outro problema com o convencional Singletons são de que depois de implementar Serializable interface, eles não permanecem Singleton, porque readObject() método sempre retornam uma nova instância como construtor em Java.Isto pode ser evitado pelo uso de readResolve() e descartar a recém-criada instância, substituindo com singleton, como abaixo

 // readResolve to prevent another instance of Singleton
 private Object readResolve(){
     return INSTANCE;
 }

Isto pode tornar-se ainda mais complexo se a sua Classe Singleton manter o estado, como você precisa para torná-los transitórios, mas com no Enum Singleton, a Serialização é garantido pela JVM.


Boa Leitura

  1. Padrão Singleton
  2. Enums, Singletons e Desserialização
  3. Verificou duas vezes fecho e o padrão Singleton

Pode ser um pouco tarde para o jogo, mas há um monte de nuance para a implementação de um singleton.O titular padrão não pode ser utilizado em muitas situações.E IMO quando utilizar um voláteis, você também deve usar uma variável local.Vamos começar pelo início e iterar sobre o problema.Você verá o que quero dizer.


A primeira tentativa pode ser algo como:

public class MySingleton {

     private static MySingleton INSTANCE;

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

        return INSTANCE;
    }
    ...
}

Aqui temos o MySingleton classe que tem um membro estático privado chamado de INSTÂNCIA, e um método estático público chamado getInstance().A primeira vez getInstance() é chamado, o membro de INSTÂNCIA é nulo.O fluxo será, em seguida, cair para a criação de condições e de criar uma nova instância do MySingleton classe.As chamadas subsequentes para getInstance() vai descobrir que a variável de INSTÂNCIA já está definido e, portanto, não crie outro MySingleton instância.Isso garante que há apenas uma instância de MySingleton que é compartilhada entre todos os chamadores de getInstance().

Mas esta implementação tem um problema.Aplicações Multi-tarefa vai ter uma condição de corrida na criação de instância única.Se vários threads de execução bater o getInstance() método (ou todo) o mesmo tempo, para que cada um veja o membro de INSTÂNCIA como null.Isto irá resultar em que cada thread de criar um novo MySingleton instância e, posteriormente, definir o membro de INSTÂNCIA.


private static MySingleton INSTANCE;

public static synchronized MySingleton getInstance() {
    if (INSTANCE == null) {
        INSTANCE = new MySingleton();
    }

    return INSTANCE;
}

Aqui usamos a palavra-chave sincronizados na assinatura do método para sincronizar o getInstance() método.Isso certamente vai consertar a nossa condição de corrida.Threads de agora irá bloco e inserir o método de uma em uma hora.Mas ele também cria um problema de desempenho.Não apenas para a implementação de sincronizar a criação de instância única, ele sincroniza todas as chamadas para getInstance(), incluindo lê.Lê não precisam ser sincronizados, eles simplesmente retornar o valor de INSTÂNCIA.Desde que lê vai fazer a maior parte de nossas chamadas (lembre-se, a instanciação só acontece na primeira chamada), vamos incorrer desnecessário, o desempenho atingido por sincronizar todo o método.


private static MySingleton INSTANCE;

public static MySingleton getInstance() {
    if (INSTANCE == null) {
        synchronize(MySingleton.class) {
            INSTANCE = new MySingleton();
        }
    }

    return INSTANCE;
}

Aqui, passamos a sincronização a partir do método de assinatura, para um bloco sincronizado que envolve a criação do MySingleton instância.Mas será que isso resolve o nosso problema?Bem, estamos bloqueando não lê, mas temos tido também um passo para trás.Vários threads vai bater o getInstance() o método em ou em torno do mesmo tempo e todos eles vão ver o membro de INSTÂNCIA como null.Eles irão, em seguida, bater o bloco sincronizado, onde se pode obter o bloqueio e criar a instância.Quando o thread sai o bloco, os outros segmentos contenderei para o bloqueio, e um por um, cada thread irá cair através do bloco e criar uma nova instância da nossa classe.Então, estamos de volta onde começamos.


private static MySingleton INSTANCE;

public static MySingleton getInstance() {
    if (INSTANCE == null) {
        synchronized(MySingleton.class) {
            if (INSTANCE == null) {
                INSTANCE = createInstance();
            }
        }
    }

    return INSTANCE;
}

Aqui temos o problema de uma outra seleção a partir de DENTRO do bloco.Se o membro de INSTÂNCIA já tenha sido definido, vamos deixar de inicialização.Isso é chamado de double-checked locking.

Isso resolve o nosso problema de múltiplas instâncias.Mas, mais uma vez, a nossa solução tem apresentado um outro desafio.Outros threads não podem "ver" que o membro de INSTÂNCIA foi atualizado.Isto é devido a como o Java otimiza as operações de memória.Threads copiar os valores originais das variáveis da memória principal para a CPU cache.Alterações de valores de são então gravados, e ler, que o cache.Este é um recurso de Java, projetado para otimizar o desempenho.Mas isso cria um problema para a nossa implementação singleton.Uma segunda thread que está sendo processado por uma CPU diferente ou núcleo, usando um cache diferentes — não vai ver as alterações feitas pelo primeiro.Isso fará com que o thread de segundo para ver o membro de INSTÂNCIA como nulo forçando uma nova instância do nosso singleton para ser criado.


private static volatile MySingleton INSTANCE;

public static MySingleton getInstance() {
    if (INSTANCE == null) {
        synchronized(MySingleton.class) {
            if (INSTANCE == null) {
                INSTANCE = createInstance();
            }
        }
    }

    return INSTANCE;
}

Vamos resolver isso usando a palavra-chave volátil sobre a declaração do membro de INSTÂNCIA.Isso fará com que o compilador sempre ler e escrever, a memória principal, e não o cache da CPU.

Mas esta simples mudança tem um custo.Porque estamos ignorando o cache da CPU, vamos tomar um desempenho cada vez que operamos no voláteis membro de INSTÂNCIA — o que vamos fazer 4 vezes.Verificamos a existência (1 e 2), defina o valor de (3) e, em seguida, retornar o valor de (4).Pode-se argumentar que esse caminho é o da franja caso, como temos apenas criar a instância durante a primeira chamada do método.Talvez um desempenho na criação é tolerável.Mas mesmo o nosso principal caso de uso, lê, vai operar na voláteis membro duas vezes.Uma vez que a verificação de existência, e novamente para retornar o seu valor.


private static volatile MySingleton INSTANCE;

public static MySingleton getInstance() {
    MySingleton result = INSTANCE;
    if (result == null) {
        synchronized(MySingleton.class) {
            result = INSTANCE;
            if (result == null) {
                INSTANCE = result = createInstance();
            }
        }
    }

    return result;
}

Desde a perda de desempenho é devido à operação diretamente no voláteis membro, vamos definir uma variável local para o valor da voláteis e operar sobre a variável local em vez disso.Isso irá diminuir o número de vezes em que operamos no voláteis, assim, recuperar alguns dos nossos perdeu desempenho.Note que temos para definir a nossa variável local novamente quando entramos no bloco sincronizado.Isto garante que ele é atualizado com todas as alterações que ocorreram enquanto estávamos esperando o bloqueio.

Eu escrevi um artigo sobre isso recentemente. A Desconstrução Do Singleton.Você pode encontrar mais informações sobre esses exemplos e um exemplo do "titular" padrão de lá.Há também um exemplo do mundo real, mostrando a dupla marcada voláteis abordagem.Espero que isso ajude.

There are 4 ways to create a singleton in java.

1- eager initialization singleton

    public class Test{
        private static final Test test = new Test();
        private Test(){}
        public static Test getTest(){
            return test;
        }
    }

2- lazy initialization singleton (thread safe)

    public class Test {
         private static volatile Test test;
         private Test(){}
         public static Test getTest() {
            if(test == null) {
                synchronized(Test.class) {
                    if(test == null){test = new Test();
                }
            }
         }

        return test;
    }


3- Bill Pugh Singleton with Holder Pattern (Preferably the best one)

    public class Test {

        private Test(){}

        private static class TestHolder{
            private static final Test test = new Test();
        }

        public static Test getInstance(){
            return TestHolder.test;
        }
    }

4- enum singleton
      public enum MySingleton {
        INSTANCE;
    private MySingleton() {
        System.out.println("Here");
    }
}

Isso é como implementar um simples singleton:

public class Singleton {
    // It must be static and final to prevent later modification
    private static final Singleton INSTANCE = new Singleton();
    /** The constructor must be private to prevent external instantiation */ 
    private Singleton(){}
    /** The public static method allowing to get the instance */
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

Esta é a maneira correta de criar seu preguiçoso singleton:

public class Singleton {
    // The constructor must be private to prevent external instantiation   
    private Singleton(){}
    /** The public static method allowing to get the instance */
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
    /** 
     * The static inner class responsible for creating your instance only on demand,
     * because the static fields of a class are only initialized when the class
     * is explicitly called and a class initialization is synchronized such that only 
     * one thread can perform it, this rule is also applicable to inner static class
     * So here INSTANCE will be created only when SingletonHolder.INSTANCE 
     * will be called
     */
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
}

Você precisa verificar a linguagem se você precisa carregar a variável de instância de uma classe preguiçosamente.Se você precisa carregar uma variável estática ou um singleton preguiçosamente, você precisa initilization na demanda titular expressão idiomática.

Além disso, se o singleton precisa ser seriliazble, todos os outros campos precisa ser transitória e readResolve() o método deve ser aplicado a fim de manter o objeto singleton invariável.Caso contrário, cada vez que o objeto é desserializado, uma nova instância do objeto será criado.O que readResolve() faz é substituir o novo objeto de leitura por readObject(), o que obrigou a que o novo objeto a ser coletados como lixo, como não há nenhuma variável que faz referência a ele.

public static final INSTANCE == ....
private Object readResolve() {
  return INSTANCE; // original singleton instance.
} 

Várias formas de tornar o objeto singleton:

  1. Como por Joshua Bloch - Enum seria o melhor.

  2. você pode usar o dobro de verificação de bloqueio também.

  3. Mesmo interior de classe estática pode ser usado.

Enum singleton

A maneira mais simples de implementar um Singleton que é thread-safe está usando um Enum

public enum SingletonEnum {
  INSTANCE;
  public void doSomething(){
    System.out.println("This is a singleton");
  }
}

Este código funciona desde a introdução do Enum no Java 1.5

Verificado duas vezes fecho

Se você quiser o código de um "clássico" singleton, que funciona em um ambiente multithread (a partir do Java 1.5) você deve usar este.

public class Singleton {

  private static volatile Singleton instance = null;

  private Singleton() {
  }

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

Este não é thread-safe, antes 1.5 porque a implementação de palavra-chave volátil foi diferente.

Início de carregamento Singleton (funciona mesmo antes de o Java 1.5)

Esta implementação instancia o singleton quando a classe é carregada e fornece segurança do thread.

public class Singleton {

  private static final Singleton instance = new Singleton();

  private Singleton() {
  }

  public static Singleton getInstance() {
    return instance;
  }

  public void doSomething(){
    System.out.println("This is a singleton");
  }

}

Para JSE 5.0 e acima de levar o Enum abordagem, caso contrário, use static singleton titular abordagem ( (um lazy loading descrito por Bill Pugh).Última solução também é thread-safe sem a necessidade especial de construções de linguagem (i.e.voláteis ou sincronizados).

Outro argumento freqüentemente usado contra Singletons são a sua capacidade de teste de problemas.Singletons não são facilmente mockable para fins de teste.Se esse for um problema, eu gostaria de fazer as seguintes modificações:

public class SingletonImpl {

    private static SingletonImpl instance;

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

    public static void setInstance(SingletonImpl impl) {
        instance = impl;
    }

    public void a() {
        System.out.println("Default Method");
    }
}

Adicionado setInstance o método permite a definição de uma maquete de implementação da classe singleton durante os testes:

public class SingletonMock extends SingletonImpl {

    @Override
    public void a() {
        System.out.println("Mock Method");
    }

}

Isto também funciona com o início de inicialização abordagens:

public class SingletonImpl {

    private static final SingletonImpl instance = new SingletonImpl();

    private static SingletonImpl alt;

    public static void setInstance(SingletonImpl inst) {
        alt = inst;
    }

    public static SingletonImpl getInstance() {
        if (alt != null) {
            return alt;
        }
        return instance;
    }

    public void a() {
        System.out.println("Default Method");
    }
}

public class SingletonMock extends SingletonImpl {

    @Override
    public void a() {
        System.out.println("Mock Method");
    }

}

Isto tem a desvantagem de expor esta funcionalidade normal de aplicação.Outros desenvolvedores de trabalho em que o código poderia ser tentado a usar o setInstance método para alterar alterar uma função específica e, assim, mudar a totalidade do pedido de comportamento, portanto, este método deve conter, no mínimo, um bom aviso no javadoc.

Ainda, para a possibilidade de maquete-teste (quando necessário), este código de exposição, pode ser um preço aceitável a pagar.

mais simples classe singleton

public class Singleton {
  private static Singleton singleInstance = new Singleton();
  private Singleton() {}
  public static Singleton getSingleInstance() {
    return singleInstance;
  }
}

Eu ainda acho que depois que o java 1.5, enum é o melhor disponível implementação singleton disponível como ele também garante que, mesmo em multi threaded ambientes - apenas uma instância é criada.

public enum Singleton{ INSTANCE; }

e você está feito !!!

Ter um olhar para este post.

Exemplos de GoF Padrões de Projeto em Java do núcleo de bibliotecas

A partir de a melhor resposta "Singleton" a seção,

Singleton (do grupo por creational métodos de retornar a mesma instância (geralmente de si mesmo) sempre)

  • o java.lang.Tempo de execução#getRuntime()
  • o java.awt.Área de trabalho#getDesktop()
  • o java.lang.Sistema de#getSecurityManager()

Você também pode aprender com o exemplo de Singleton de Java nativo de classes próprias.

O melhor padrão singleton que eu já vi utiliza o Fornecedor de interface.

  • É genérico e reutilizável
  • Ele suporta a inicialização lenta
  • É só sincronizado até que ele tenha sido inicializado, o bloqueio do fornecedor é substituído com um non-blocking fornecedor.

Veja abaixo:

public class Singleton<T> implements Supplier<T> {

    private boolean initialized;
    private Supplier<T> singletonSupplier;

    public Singleton(T singletonValue) {
        this.singletonSupplier = () -> singletonValue;
    }

    public Singleton(Supplier<T> supplier) {
        this.singletonSupplier = () -> {
            // The initial supplier is temporary; it will be replaced after initialization
            synchronized (supplier) {
                if (!initialized) {
                    T singletonValue = supplier.get();
                    // Now that the singleton value has been initialized,
                    // replace the blocking supplier with a non-blocking supplier
                    singletonSupplier = () -> singletonValue;
                    initialized = true;
                }
                return singletonSupplier.get();
            }
        };
    }

    @Override
    public T get() {
        return singletonSupplier.get();
    }
}

Às vezes um simples "static Foo foo = new Foo();"não é o suficiente.Basta pensar de alguns básicas de inserção de dados que você deseja fazer.

Por outro lado, você teria para sincronizar qualquer método que instancia o singleton variável como tal.A sincronização não é ruim como tal, mas pode levar a problemas de desempenho ou de bloqueio (em muito raras situações, utilizando este exemplo.A solução é

public class Singleton {

    private static Singleton instance = null;

    static {
          instance = new Singleton();
          // do some of your instantiation stuff here
    }

    private Singleton() {
          if(instance!=null) {
                  throw new ErrorYouWant("Singleton double-instantiation, should never happen!");
          }
    }

    public static getSingleton() {
          return instance;
    }

}

Agora o que acontece?A classe é carregada através do carregador de classe.Diretamente depois da aula, foi interpretada a partir de uma Matriz de bytes, o VM executa o static { } - bloco.esse é todo o segredo:Estática-bloco é chamado somente uma vez, o tempo que a determinada classe (nome) de um determinado pacote é carregado por este carregador de classe.

public class Singleton {

    private static final Singleton INSTANCE = new Singleton();

    private Singleton(){
    if (INSTANCE != null)
        throw new IllegalStateException (“Already instantiated...”);
}

    public synchronized static Singleton getInstance() { 
    return INSTANCE;

    }

}

Como nós adicionamos a palavra-chave Sincronizados antes de getInstance, temos evitado a condição de corrida no caso quando dois threads chamar a getInstance ao mesmo tempo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top