O padrão de singleton é o mais fácil de entender e a maneira mais fácil de escrita à mão no padrão de design, mas não há muitos pontos de conhecimento envolvidos, por isso é frequentemente usado como uma pergunta de entrevista. Geralmente, os singletons são escritos de cinco maneiras: preguiçosa, com fome, trava dupla, classes internas estáticas e enumeração. Para registrar o processo de aprendizagem, vários métodos comuns de escrita de singleton foram compilados aqui.
Bronze 5: (carregado preguiçoso, mas thread não é seguro)
Quando perguntado sobre a implementação de um padrão de singleton, a primeira reação de muitas pessoas é escrever o código a seguir, incluindo os mesmos ensinamentos em livros didáticos.
classe pública Singleton {private Static Singleton Instância; private singleton () {} public static singleton getInstance () {if (instance == null) {instance = new singleton (); } Instância de retorno; }}Esse código é simples e direto e usa o modo de carregamento atrasado, mas os threads não são seguros. Chamar o método getInstance () em um ambiente multi-thread pode fazer com que vários threads digitem o bloco de código do programa da instrução IF.
Estilo preguiçoso: sincronizado (preguiçoso, seguro para roscas, mas não eficiente)
Para resolver o problema acima, a maneira mais fácil é definir o método GetInstance () inteiro para sincronizado.
classe pública Singleton {private Static Singleton Instância; private singleton () {} public static sincronizado singleton getInstance () {if (instance == null) {instance = new singleton (); } Instância de retorno; }}Embora seja seguro para roscas e atrasado, não é eficiente. Porque a qualquer momento, pode haver apenas um thread chamando o método getInstance (). No entanto, a operação sincronizada precisa ser necessária apenas na primeira chamada, ou seja, quando o objeto Singleton Instância é criado pela primeira vez. Esse padrão faz com que apenas um thread acesse o método getInstance () por vez, mesmo depois que o singleton for criado, o que pode levar a possíveis problemas de desempenho. Isso leva a um bloqueio de verificação dupla.
Estilo faminto: campo final estático (não com carga preguiçosa)
Esse método é muito simples, porque a instância de um singleton é declarada final estática e é inicializada quando a classe é carregada na memória pela primeira vez; portanto, criar um objeto de instância é segura para thread (garantida pela implementação da JVM).
classe pública Singleton {// Inicializa a instância do Singleton Final Singleton, da Singleton (new Singleton (); private singleton () {} public static singleton getInstance () {// singleton com instância de retorno de fábrica estática; }}Não é um modo de carregamento preguiçoso, a instância será inicializada desde o início após o carregamento da classe, mesmo que o cliente não chame o método getInstance (). Isso levará a algumas restrições de uso: por exemplo, a criação de uma instância de singleton depende de parâmetros ou arquivos de configuração. Antes de getInstance (), um determinado método deve ser chamado para definir parâmetros para ele, para que esse método de escrita singleton não seja usado. Métodos semelhantes incluem:
classe pública singleton {public static final singleton instância = new singleton (); // Singleton com campo final público Singleton () {}} // <eficaz java> Página 14 diz a diferença entre os doisVerifique o bloqueio de duas
O padrão de travamento verificado duplo é um método de bloqueio usando blocos síncronos. Os programadores chamam isso de bloqueio de verificação dupla, porque haverá duas instância de verificação == NULL, uma vez fora do bloco de sincronização e uma vez dentro do bloco de sincronização. Por que precisamos verificar novamente no bloco de sincronização? Como vários threads podem entrar se fora do bloco de sincronização, se nenhuma verificação secundária for realizada no bloco de sincronização, vários objetos de instância serão gerados.
public static singleton getingleton () {if (instance == null) {// single verificado sincronizado (singleton.class) {if (instance == null) {// verificado duplo = new singleton (); }}} retornar a instância;}Esse código parece perfeito, mas infelizmente é problemático. O principal é a instância da sentença = new Singleton (). Esta não é uma operação atômica. De fato, essa frase na JVM faz aproximadamente as três coisas a seguir.
No entanto, há otimização da reordenação de instruções no compilador JIT da JVM. Em outras palavras, a ordem da segunda e terceira etapas acima não pode ser garantida e a ordem final de execução pode ser 1-2-3 ou 1-3-2. Se for o último, ele será antecipado pelo thread 2 antes da execução de 3 e 2 não será executada. No momento, a instância já é não nula (mas não é inicializada); portanto, o Thread 2 retornará diretamente a instância e a usará e, naturalmente, relatará um erro. Para fazer isso, precisamos declarar a variável de instância como volátil.
classe pública Singleton {private Volátil Static Singleton Instância; // Declare como Volatile Private Singleton () {} public static singleton getsingleton () {if (instance == null) {synchronized (singleton.class) {if (instance == null) {instance = new Singleton (); }} retornar a instância; }}No entanto, é importante observar que ainda existem problemas com o bloqueio de verificação dupla de versões voláteis antes do Java 1.5. Esse problema foi corrigido apenas no Java 1.5, para que você possa usar o volátil depois disso.
Classe interna estática: IODH, inicialização da demanda por demanda
Esse padrão combina as classes internas estáticas da Java e o conhecimento de bloqueio de sincronização padrão com vários threads e implementa inteligentemente o carregamento da latência e a segurança da linha.
classe pública singleton {private singleton () {} classe estática privada lazyholder {private static final singleton instância = new singleton (); } public static singleton getInstance () {// da Wikipedia Return lazyholder.instance; }}Uma classe interna estática é equivalente à parte estática de sua classe externa. Seus objetos não dependem de objetos de classe externa, para que possam ser criados diretamente. As classes internas estáticas serão reproduzidas apenas quando forem usadas pela primeira vez.
Bloqueio de sincronização padrão multithread
Como todos sabemos, no desenvolvimento multithread, para resolver o problema de simultaneidade, ele deve usar principalmente sincronizado para adicionar mutexes para controle de sincronização. Mas, em alguns casos, a JVM já executa implicitamente a sincronização para você e, nesses casos, não há necessidade de executar manualmente o controle de sincronização. Essas situações incluem :
1. Ao inicializar os dados por um inicializador estático (inicializador em um campo estático ou em um bloco estático {})
2. Ao acessar o campo final
3. Ao criar um objeto antes de criar um tópico
4. Quando o tópico pode ver o objeto, ele processará
Enum
A partir do Java 1.5, basta escrever um tipo de enumeração contendo um único elemento:
public Enum Singleton {Instância;}Esse método é funcionalmente semelhante ao método de domínio público, mas é mais conciso e fornece um mecanismo de serialização livre de carga, impedindo absolutamente a instanciação múltipla, mesmo quando enfrentando ataques complexos de serialização ou reflexão. Embora essa abordagem não tenha sido amplamente adotada, os tipos de enumeração de elementos únicos se tornaram a melhor maneira de implementar singleton.
--------------------------------------------------------------------------------------------------------------------------------------------------
1. Quais são os detalhes da final estática
2. A inicialização da atribuição está no campo estático em sequência e no bloco de código estático?
3. Como escrever um padrão de singleton para classes internas estáticas
4. Os exemplos na análise e aplicação do Java EE Design Pattern realmente tem um efeito preguiçoso?
O exposto acima é todo o conteúdo deste artigo. Espero que o conteúdo deste artigo seja de ajuda para estudar ou trabalhar de todos. Eu também espero apoiar mais wulin.com!