O objetivo do padrão Singleton é garantir que uma classe tenha apenas uma instância e também forneça um ponto de acesso global para ela. Para impedir que outros trabalhadores instanciem nossa classe,
Você pode criar um construtor exclusivo para esta classe e definir o visível do construtor como privado. Vale a pena notar que, se criarmos outros construtores não privados, ou não fizermos nenhuma menção à classe
Para os construtores, outras pessoas ainda podem instanciar nossa classe. Se não queremos criar um objeto Singleton com antecedência, podemos esperar até a primeira vez que usamos o objeto Singleton, ou seja,
Inicialização do atraso. Existem duas razões para a inicialização da inicialização dos objetos de singleton:
1. Talvez no tempo de inicialização estática, você não tenha informações suficientes sobre como inicializar um objeto Singleton.
2. O objetivo de selecionar uma inicialização de lag Singleton pode ser aguardar recursos como conexões de banco de dados, especialmente em aplicativos em que esse singleton não é necessário em determinadas sessões específicas.
Se um singleton for inicializado em um ambiente multithread, devemos ter cuidado para impedir que vários threads inicializem ao mesmo tempo.
Normalmente, o padrão de singleton é construído na linguagem Java:
Caminho preguiçoso: refere -se à instância global de singleton que está sendo construída quando é usada pela primeira vez. Atraso inicialização.
Método Hungry Man: refere -se à instância única global que está sendo construída durante o carregamento da classe. Inicialização urgente.
1. Singleton chinês faminto
classe pública singleton1 {private singleton1 () {} // define sua própria instância internamente. // Observe que isso é privado. Private static singleton1 instância = new singleton1 (); /** * // ** * Aqui está um método estático para acesso externo a esta classe, que pode ser acessada diretamente * @return */public static singleton1 getInstance () {retorna instância; }}2. Classe de singleton preguiçosa
classe pública singleton2 {private static singleton2 instância = null; /*** // *** Este método é aprimorado em comparação com o acima. Não requer geração de objetos sempre, mas a primeira vez * gera instâncias quando usadas, o que melhora a eficiência! * @return */ public static singleton2 getInstance () {if (instance == null) instância = new singleton2 (); instância de retorno; }}A seguir, são apresentados os principais problemas de múltiplos threading. Em singletons preguiçosos, não há nenhum problema com o encadeamento único, mas, quando multi-threading, pode haver duas ou mais instâncias singletion2.
Por exemplo: quando o thread 1 julga que a instância == NULL é verdadeira, ao digitalizar a nova operação, antes de executar a nova operação e depois de executar a nova operação, o Thread 2 apenas executa a operação de julgamento e a instância ainda é nula. Portanto, o Thread 2 também executará a nova operação. E assim, sob alta simultaneidade, pode haver duas ou mais instâncias de singletion2. Obviamente, isso está incorreto.
Portanto, altere o código da seguinte maneira:
classe pública singleton3 {private static singleton3 instância = null; /*** // *** Este método é aprimorado em comparação com o acima. Não exige que o objeto seja gerado sempre, mas a primeira vez * gera instâncias quando usado, o que melhora a eficiência! * Para evitar erros no threading multi, o sinalizador de sincronização foi adicionado * @return */ public static sincronizado singleton3 getInstance () {if (instance == null) instância = new singleton3 (); instância de retorno; }}Mas isso cria outro problema. Os métodos são sincronizados toda vez que a instância é recuperada. Obviamente, o desempenho é muito afetado; portanto, continue a alterar o código da seguinte forma:
Volátil, substitua a sincronização por um custo menor
Por que é mais barato que a sincronização?
O custo da sincronização é determinado principalmente por sua gama de cobertura. Se a faixa de cobertura de sincronização puder ser reduzida, o desempenho do programa poderá ser bastante aprimorado.
A cobertura do volátil está apenas no nível variável. Portanto, seu custo de sincronização é muito baixo.
Qual é o princípio do volátil?
A semântica da Volátil deve dizer ao processador para não me colocar na memória de trabalho, opere -me diretamente na memória principal. (Veja o modelo de memória Java para obter a memória de trabalho para obter detalhes)
Portanto, ao acessar a variável, eles operam diretamente a memória principal, que essencialmente atinge o compartilhamento de variáveis.
Quais são as vantagens do volátil?
1 Taxa de transferência de programa maior
2. Menor código para implementar multi-threading
3. O programa tem melhor escalabilidade
4. É mais fácil de entender, e não há necessidade de custos de aprendizado muito altos.
Quais são as desvantagens do volátil?
1. Propenso a problemas
2. É difícil projetar
O Volatile usa o JDK requer a versão 1.5 e acima.
O código aprimorado é o seguinte (também chamado de bloqueio duplo):
classe pública singleton4 {private static volátil singleton4 instância; /*** // *** bloqueio duplo para obter aplicativos multi-threading e otimização de desempenho* @return*/public static singleton4 getInstance () {if (instance == null) {synchronized (singleton4.class) {// 1 if (instance == null)/2 instância = novo singleton4 (); // 3}} retornar a instância; }}