conceito:
O padrão de singleton em Java é um padrão de design comum. O padrão de singleton é dividido em três tipos: Lazy Singleton, Hungry Singleton e Singleton registrado.
O modo Singleton tem as seguintes características:
1. Só pode haver uma instância em uma aula de singleton.
2. A classe Singleton deve criar sua própria instância única.
3. A classe Singleton deve fornecer esta instância a todos os outros objetos.
O padrão Singleton garante que uma classe tenha apenas uma instância e a instante e forneça essa instância a todo o sistema. Em sistemas de computadores, objetos de driver para pools de threads, caches, objetos de log, caixas de diálogo, impressoras e placas de gráficos são frequentemente projetadas como singletons. Esses aplicativos têm mais ou menos a funcionalidade de um gerente de recursos. Cada computador pode ter várias impressoras, mas apenas um spooler da impressora pode estar disponível para evitar dois trabalhos de impressão sendo produzidos para a impressora ao mesmo tempo. Cada computador pode ter várias 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 simultaneamente por duas solicitações. Em suma, escolher um modelo de singleton é evitar estados inconsistentes e evitar o agressor político.
Aqui estão dois tipos de introduções: preguiçoso e faminto
1. Carregar imediatamente/faminto estilo
Antes de ligar para o método, a instância foi criada, código:
pacote com.weishiyao.learn.day8.singleton.ep1; public class myObject {// carregando agora == Modo do mal myObject privado myObject = new MyObject (); private myObject () {} public static myObject getInstance () {// Esta versão está carregando agora // A desvantagem desta versão do código é que não pode haver outras variáveis de instância // porque o método getInstance () não é sincronizado; }} Crie uma aula de thread
pacote com.weishiyao.learn.day8.singleton.ep1; public classe mythread estende thread {@Override public void run () {System.out.println (myObject.getInstance (). hashcode ()); }} Crie uma classe de corrida
pacote com.weishiyao.learn.day8.singleton.ep1; public class Run {public static void main (string [] args) {mythread t1 = new mythread (); Mythread t2 = new mythread (); Mythread t3 = new mythread (); t1.start (); t2.start (); t3.start (); }} Resultados de execução
167772895
167772895
167772895
HashCode é o mesmo valor, o que significa que o objeto também é o mesmo, o que significa que o modo de carregamento instantâneo é implementado.
2. Carrego preguiçoso/preguiçoso
A instância será criada após a chamada do método. O plano de implementação pode ser colocar instanciação no construtor sem parâmetros, para que uma instância do objeto seja criada apenas quando o método for chamado. Código:
pacote com.weishiyao.learn.day8.singleton.ep2; classe pública myObject {private static myObject myObject; private myObject () {} public static myObject getInstance () {// atraso no carregamento if (myObject! = null) {} else {myObject = new MyObject (); } retornar myObject; }} Crie uma aula de thread
pacote com.weishiyao.learn.day8.singleton.ep2; public class mythread estende thread {@Override public void run () {System.out.println (myObject.getInstance (). hashcode ()); }} Crie uma classe de corrida
pacote com.weishiyao.learn.day8.singleton.ep2; public class Run {public static void main (string [] args) {mythread t1 = new mythread (); t1.start (); }}Resultados de execução
167772895
Embora uma instância de um objeto seja tomada, se estiver em um ambiente multithread, ocorrerão várias instâncias, o que não é um padrão de singleton
Execute a aula de teste
pacote com.weishiyao.learn.day8.singleton.ep2; public class Run {public static void main (string [] args) {mythread t1 = new mythread (); Mythread t2 = new mythread (); Mythread t3 = new mythread (); Mythread t4 = new mythread (); Mythread t5 = new mythread (); t1.start (); t2.start (); t3.start (); t4.start (); t5.start (); }}Resultados de execução
980258163
1224717057
1851889404
188820504
1672864109
Como há um problema, precisamos resolver o problema. Solução multithread no modo preguiçoso, código:
A primeira solução, mais comumente, adicionar sincronizada e sincronizada pode ser adicionada a diferentes posições
O primeiro método bloqueia
pacote com.weishiyao.learn.day8.singleton.ep3; public class myObject {private static myObject myObject; private myObject () {} sincronizada public estática estática myObject getInstance () {// carregamento de atraso, tente {if (myObject! = null) {} else {// simular alguma preparação antes de criar um thread.sleep (2000); myObject = new MyObject (); }} catch (interruptEdException e) {e.printStackTrace (); } retornar myObject; }}Esse esquema de sincronização sincronizado resulta em muito ineficiente e todo o método está bloqueado
O segundo esquema de uso sincronizado
pacote com.weishiyao.learn.day8.singleton.ep3; public class myObject {private static myObject myObject; private myObject () {} public static myObject getInstance () {// carregamento de atraso, tente {synchronized (myObject.class) {if (myObject! = null) {} else {// simular algum trabalho de preparação antes de criar um objeto Thread.sleep (2000); myObject = new MyObject (); }}} catch (interruptEdException e) {e.printStackTrace (); } retornar myObject; }} Este método também é muito baixa eficiência. Todos os códigos no método estão bloqueados. Você só precisa bloquear o código da chave. O terceiro plano de uso sincronizado
pacote com.weishiyao.learn.day8.singleton.ep3;
classe pública myObject {private estático myObject myObject; private myObject () {} public static myObject getInstance () {// carregamento de atraso, tente {if (myObject! = null) {} else {// simular alguma preparação antes de criar o thread.sleep (2000); sincronizado (myObject.class) {myObject = new MyObject (); }}} catch (interruptEdException e) {e.printStackTrace (); } retornar myObject; }}Esta parece ser a melhor solução, mas depois de executá-la, achei que é na verdade
resultado:
1224717057
971173439
1851889404
1224717057
1672864109
Por que?
Embora a afirmação que cria um objeto esteja bloqueada, apenas um thread pode concluir a criação de cada vez, depois que o primeiro thread chegar para criar o objeto, o segundo thread ainda pode continuar a criá -lo, porque apenas travamos a declaração de criação, essa solução de problema
pacote com.weishiyao.learn.day8.singleton.ep3; public class myObject {private static myObject myObject; private myObject () {} public static myObject getInstance () {// carregamento de atraso, tente {if (myObject! = null) {} else {// simular alguma preparação antes de criar um thread.sleep (2000); sincronizado (myObject.class) {if (myObject == null) {myObject = new MyObject (); }}}} catch (interruptEdException e) {e.printStackTrace (); } retornar myObject; }}Basta adicionar outro julgamento à fechadura para garantir um singleton. Este é o mecanismo de verificação dupla DCL
Os resultados são os seguintes:
1224717057
1224717057
1224717057
1224717057
1224717057
3. Use classes estáticas internas para implementar casos únicos
Código principal
pacote com.weishiyao.learn.day8.singleton.ep4; public class myObject {// classe interna Método Classe estática privada myobjecthandler {myObject privado myObject = new myObject (); } public myObject () {} public static myObject getInstance () {return myobjecthandler.myobject; }} Código da classe Thread
pacote com.weishiyao.learn.day8.singleton.ep4; public classe mythread estende thread {@Override public void run () {System.out.println (myObject.getInstance (). hashcode ()); }} Executar aula
pacote com.weishiyao.learn.day8.singleton.ep4; public class Run {public static void main (string [] args) {mythread t1 = new mythread (); Mythread t2 = new mythread (); Mythread t3 = new mythread (); Mythread t4 = new mythread (); Mythread t5 = new mythread (); t1.start (); t2.start (); t3.start (); t4.start (); t5.start (); }}resultado
1851889404
1851889404
1851889404
1851889404
1851889404
Através de classes estáticas internas, um padrão singleton seguro para roscas é obtido
4. Serialize e desserialize padrões de singleton
As classes estáticas embutidas podem atingir problemas de segurança de encadeamentos, mas se você encontrar objetos serializados, o resultado obtido usando o método padrão ainda é vários casos.
Código MyObject
pacote com.weishiyao.learn.day8.singleton.ep5; importar java.io.Serializable; public class myObject implementa serializável { / ** * * / private estático final serialversionuid = 888L; // Classe de classe interna Método Private estático MyObJectHandler {private estático myObject myObject = new MyObject (); } public myObject () {} public static myObject getInstance () {return myobjecthandler.myobject; } // protegido myObject readResolve () {// System.out.println ("O método readResolve foi chamado!"); // retorna myobjecthandler.myobject; //}} Negócios
pacote com.weishiyao.learn.day8.singleton.ep5; importar java.io.file; importar java.io.fileInputStream; importar java.io.filenotfoundException; importação java.io.fileoutTutream; importar java.io.ioxception; importação java.io.io.io. java.io.ObjectOutputStream; public class SaveAndRead {public static void main (string [] args) {try {myObject myObject = myObject.getInstance (); FileOutputStream fosref = new FileOutputStream (novo File ("myObjectfile.txt")); ObjectOutputStream oosref = new ObjectOutputStream (FOSREF); oosref.writeObject (myObject); oosref.close (); fosref.close (); System.out.println (myObject.hashcode ()); } catch (filenotfoundException e) {e.printStackTrace (); } catch (ioexception e) {e.printStackTrace (); } FileInputStream fisref; tente {fisref = new FileInputStream (novo arquivo ("myObjectfile.txt"); ObjectInputStream iosref = new ObjectInputStream (fisref); MyObject myObject = (myObject) iosref.readObject (); iosref.close (); fisref.close (); System.out.println (myObject.hashcode ()); } catch (filenotfoundException e) {e.printStackTrace (); } catch (ioexception e) {e.printStackTrace (); } catch (classNotFoundException e) {e.printStackTrace (); }}}resultado
970928725
1099149023
Dois códigos de hash diferentes provam que eles não são o mesmo objeto. Solução, adicione o seguinte código
MyObject protegido readResolve () {System.out.println ("O método readResolve foi chamado!"); return myobjecthandler.myObject; }Chamado durante a deserialização, você pode obter o mesmo objeto
System.out.println (myObject.readResolve (). Hashcode ());
resultado
1255301379
O método ReadResolve foi chamado!
1255301379
O mesmo hashcode prova que o mesmo objeto é obtido
5. Use blocos de código estático para implementar um único caso
O código no bloco de código estático já foi executado ao usar a classe; portanto, o recurso do código estático rápido pode ser usado para implementar o modo de lucro simples.
Classe MyObject
pacote com.weishiyao.learn.day8.singleton.ep6; public class myObject {private static myObject instância = null; private myObject () {super (); } static {instance = new MyObject (); } public static myObject getInstance () {retorna instância; }} Classe de thread
pacote com.weishiyao.learn.day8.singleton.ep6; public classe mythread estende thread {@Override public void run () {for (int i = 0; i <5; i ++) {System.out.println (myObject.getInstance (). Hashcode ()); }}} Executar aula
pacote com.weishiyao.learn.day8.singleton.ep6; public class Run {public static void main (string [] args) {mythread t1 = new mythread (); Mythread t2 = new mythread (); Mythread t3 = new mythread (); Mythread t4 = new mythread (); Mythread t5 = new mythread (); t1.start (); t2.start (); t3.start (); t4.start (); t5.start (); }}Resultados em execução:
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
1678885403
O padrão de singleton segura por threads é obtido com sucesso através do recurso de executar apenas blocos de código estático uma vez.
6. Use os tipos de dados da enum enum para implementar o modo singleton
As características do enum enum e dos blocos de código estático são semelhantes. Ao usar enums, o construtor será chamado automaticamente e também pode ser usado para implementar o modo singleton.
Classe MyObject
pacote com.weishiyao.learn.day8.singleton.ep7; importar java.sql.connection; importar java.sql.driverManager; importar java.sql.sqlexception; public enum myObject {ConnectionFactory; conexão privada de conexão; private myObject () {try {System.out.println ("O construto do MyObject foi chamado"); String url = "jdbc: mysql: //172.16.221.19: 3306/weChat_1? Useunicode = true & caracteryncoding = utf-8"; String name = "root"; String senha = "111111"; String drivername = "com.mysql.jdbc.driver"; Class.ForName (Drivername); conexão = driverManager.getConnection (URL, nome, senha); } catch (classNotFoundException e) {e.printStackTrace (); } catch (sqLexception e) {e.printStackTrace (); }} conexão pública getConnection () {return Connection; }} Classe de thread
pacote com.weishiyao.learn.day8.singleton.ep7; public classe mythread estende thread {@Override public void run () {for (int i = 0; i <5; i ++) {System.out.println (myObject.Connection.GeGeNconConCeation (). }}} Executar aula
pacote com.weishiyao.learn.day8.singleton.ep7; public classe run {public static void main (string [] args) {mythread t1 = new mythread (); Mythread t2 = new mythread (); Mythread t3 = new mythread (); Mythread t4 = new mythread (); Mythread t5 = new mythread (); t1.start (); t2.start (); t3.start (); t4.start (); t5.start (); }}Resultados de execução
Chamado de construção myObject
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
O método de escrita acima expõe a classe de enumeração, que viola o "princípio de responsabilidade única". Você pode usar uma classe para envolver a enumeração.
pacote com.weishiyao.learn.day8.singleton.ep8; importar java.sql.connection; importar java.sql.drivermanager; importar java.sql.sqLexception; public class myObject {public enum myenumsingleton {conexão de conexão; conexão privada de conexão; private myenumsingleton () {try {System.out.println ("O construto do MyObject foi chamado"); String url = "jdbc: mysql: //172.16.221.19: 3306/weChat_1? Useunicode = true & caracteryncoding = utf-8"; String name = "root"; String senha = "111111"; String drivername = "com.mysql.jdbc.driver"; Class.ForName (Drivername); conexão = driverManager.getConnection (URL, nome, senha); } catch (classNotFoundException e) {e.printStackTrace (); } catch (sqLexception e) {e.printStackTrace (); }} conexão pública getConnection () {return Connection; }} conexão estática pública getConnection () {return myenumsingleton.connectionFactory.getConnection (); }} Altere o código do thread
pacote com.weishiyao.learn.day8.singleton.ep8; public classe mythread estende thread {@Override public void run () {for (int i = 0; i <5; i ++) {System.out.println (myObject.getConnection (). Hashcode ()); }}} Como resultado, o construto myObject é chamado
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
O exposto acima resume várias situações e soluções encontradas ao combinar o modo de interesse único com multi-threading, para que possa ser revisado quando usado posteriormente.