O padrão singleton possui as seguintes características:
1. Uma classe singleton só pode ter uma instância.
2. Uma classe singleton deve criar sua própria instância exclusiva.
3. A classe singleton deve fornecer esta instância para todos os outros objetos.
O padrão singleton garante que haja apenas uma instância de uma classe, e ele se instancia e fornece essa instância para todo o sistema. Em sistemas de computador, pools de threads, caches, objetos de log, caixas de diálogo, impressoras e objetos de driver de placa gráfica são frequentemente projetados como singletons. Todos esses aplicativos têm mais ou menos a funcionalidade dos gerenciadores de recursos. Cada computador pode ter várias impressoras, mas só pode haver um spooler de impressora para evitar que dois trabalhos de impressão sejam enviados para a impressora ao mesmo tempo. Cada computador pode ter diversas portas de comunicação e o sistema deve gerenciar centralmente essas portas de comunicação para evitar que uma porta de comunicação seja chamada por duas solicitações ao mesmo tempo. Em suma, o objectivo da escolha do modo singleton é evitar estados inconsistentes e evitar políticas de longo prazo.
Primeiro, vamos dar uma olhada em uma implementação singleton clássica.
Copie o código do código da seguinte forma:
classe pública Singleton {
private static Singleton uniqueInstance = null;
Singleton privado() {
// Existe apenas para derrotar a instanciação.
}
public static Singleton getInstance() { if (uniqueInstance == null) {
instância única = new Singleton();
}
return instância única;
}
// Outros métodos...
}
Singleton evita que a classe seja instanciada externamente, limitando o método de construção a privado. Dentro do escopo da mesma máquina virtual, a única instância de Singleton só pode ser acessada através do método getInstance(). (Na verdade, é possível instanciar uma classe com um construtor privado através do mecanismo de reflexão Java, o que basicamente invalidará todas as implementações Java singleton. Esta questão não será discutida aqui. Vamos fingir que o mecanismo de reflexão não existe.)
No entanto, a implementação acima não considera questões de segurança de thread. A chamada segurança de thread significa: se houver vários threads em execução ao mesmo tempo no processo onde seu código está localizado, esses threads poderão executar esse código ao mesmo tempo. Se os resultados de cada execução forem iguais aos das execuções de thread único e os valores de outras variáveis forem os mesmos esperados, é thread-safe. Em outras palavras: a interface fornecida por uma classe ou programa é uma operação atômica para threads ou a alternância entre vários threads não causará ambigüidade nos resultados de execução da interface, o que significa que não precisamos considerar problemas de sincronização. Obviamente, a implementação acima não atende aos requisitos de segurança de thread e é provável que várias instâncias Singleton apareçam em um ambiente simultâneo.
Copie o código do código da seguinte forma:
//Classe singleton estilo Hungry. Ela foi instanciada por si mesma quando a classe foi inicializada.
classe pública Singleton1 {
//Construtor padrão privado
Singleton1 privado() {}
//Já instanciado por si só
privado estático final Singleton1 single = new Singleton1();
//método de fábrica estático
public static Singleton1 getInstance() {
retornar solteiro;
}
}
//Classe singleton preguiçosa. Instancia quando chamada pela primeira vez.
classe pública Singleton2 {
//Construtor padrão privado
Singleton2 privado() {}
//Observação, não há final aqui
privado estático Singleton2 single=null;
//método de fábrica estático
público sincronizado estático Singleton2 getInstance() {
if (único == nulo) {
único = novo Singleton2();
}
retornar solteiro;
}
}