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.day.singleton.ep; public class myObject {// carregando agora == Modo do mal myObject estático myObject = new MyObject (); private myObject () {} public staticject getInStance () {// A versão do código é a outra vez // O método getInstance () não é sincronizado //, portanto, problemas não-thread-sAFE podem ocorrer retornar myObject;}} Crie uma aula de thread
pacote com.weishiyao.learn.day.singleton.ep; a classe pública mythread estende thread {@OverridePublic void run () {System.out.println (myObject.getInstance (). hashcode ();}}} Crie uma classe de corrida
pacote com.weishiyao.learn.day.singleton.ep; public class Run {public static void main (string [] args) {mythread t = new mythread (); mythread t = new mythread (); mythread t = new mythread (); t.start (); t.start (); t.start ();}} Resultados de execução
1 167772895
2 167772895
3 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.day.singleton.ep; public class myObject {myObject privado estático myObject; private myObject () {} public static myObject getInstance () {// atraso o carregamento se (myObject! Crie uma aula de thread
pacote com.weishiyao.learn.day.singleton.ep; a classe pública mythread estende thread {@OverridePublic 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
1 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.day.singleton.ep; public class Run {public static void main (string [] args) {mythread t = new mythread (); mythread t = new mythread (); mythread t = new myth (); mythread t = new mythread (); Mythread (); t.start (); t.start (); t.start (); t.start (); t.start (); t.start (); }} Resultados de execução
1 980258163
2 1224717057
3 1851889404
4 188820504
5 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.day.singleton.ep; public class myObject {myObject privado estático myObject; private myObject () {} sincronizado public static myObject getInstance () {// atraso carregando {if (myObject! 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.day.singleton.ep; public class MyObject {myObject privado estático myObject; private myObject () {} public static myObject getInstance () {// atraso no carregamento {synchronized (MyObject.class) {) {// retarding null) {synchronized (} {if (myObject! Thread.sleep (); 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.day.singleton.ep; public class myObject {myObject privado estático myObject; private myObject () {} public static myObject getInstance () {// atraso o carregamento de tentar {if (myObject! (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:
1 1224717057
2 971173439
3 1851889404
4 1224717057
5 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.day.singleton.ep; public class myObject {myObject privado estático myObject; private myObject () {} public static myObject getInstance () {// atraso o carregamento de trabalho {if (myObject! (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:
1 1224717057
2 1224717057
3 1224717057
4 1224717057
5 1224717057
3. Use classes estáticas internas para implementar casos únicos
Código principal
pacote com.weishiyao.learn.day.singleton.ep; public class myObject {// classe interna Método estático privado estático myobjecthandler {myObject privado myObject myObject = new MyObject ();} public myObject () {} public staticject. Código da classe Thread
pacote com.weishiyao.learn.day.singleton.ep; a classe pública mythread estende thread {@OverridePublic void run () {System.out.println (myObject.getInstance (). hashcode ();}}} Executar aula
pacote com.weishiyao.learn.day.singleton.ep; public class Run {public static void main (string [] args) {mythread t = new mythread (); mythread t = new mythread (); mythread t = new myth (); mythread t = new mythread (); Mythread (); t.start (); t.start (); t.start (); t.start (); t.start (); t.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 interna MyObjecta (private; {} public static myObject getInstance () {return myobjecthandler.myObject;} // protegido myObject readResolve () {// System.out.println ("O método readResolve foi chamado!"); // retornar myObjectHandler.myobject; Negócios
pacote com.weishiyao.learn.day.singleton.ep; importar java.io.file; importar java.io.fileInputStream; importar java.io.filenotfoundException; importação java.io.iooutputputteram; importinStram.lAvStr; importação; importação; importação de java.io.io.fileoutputMeReam; importinTerReam; SaveAndRead {public static void main (string [] args) {try {myObject myObject = myObject.getInstance (); fileOutputStream fosref = new FileOutputStream (new File ("myObjectfile.txt")); objectputStream oosref = new New " ObjectOutputStream (fosref); oosref.writeObject (myObject); oosref.close (); fosref.close (); system.out.println (myObject.hashcode ());} catch (filotfoundException e) {e.PrintTacktrace ();}; {E.PrintStackTrace ();} fileInputStream fisRef; Try {fisref = new FileInputStream (new File ("myObjectfile.txt")); objectInputStream iosref = new ObjectInputStream (fisref); myObject iosref.readObject (); iosref.close (); fisref.close (); system.out.println (myObject.hashcode ());} catch (filenotfoundException e) {e.printstacktrace ();} catch (ioException e) {e.printStack (e.PrintStack (); {E.PrintStackTrace ();}}} resultado
1 970928725
2 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!"); retornar myobjecthandler.myObject;} Chamado durante a deserialização, você pode obter o mesmo objeto
System.out.println (myObject.readResolve (). Hashcode ());
resultado
1 1255301379
2 O método ReadResolve foi chamado!
3 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.day.singleton.ep; public class myObject {private static myObject instância = null; private myObject () {super ();} static {instance = new myObject ();} public static myObject getInstance () {retorn;}}}} Classe de thread
pacote com.weishiyao.learn.day.singleton.ep; public class mythread estende thread {@OverridePublic void run () {for (int i =; i <; i ++) {System.out.println (myObject.getInstance (). Hashcode ()); Executar aula
pacote com.weishiyao.learn.day.singleton.ep; public class Run {public static void main (string [] args) {mythread t = new mythread (); mythread t = new mythread (); mythread t = new myth (); mythread t = new mythread (); Mythread (); t.start (); t.start (); t.start (); t.start (); t.start (); t.start (); }} Resultados em execução:
1 1678885403
2 1678885403
3 1678885403
4 1678885403
5 1678885403
6 1678885403
7 1678885403
8 1678885403
9 1678885403
10 1678885403
11 1678885403
12 1678885403
13 1678885403
14 1678885403
15 1678885403
16 1678885403
17 1678885403
18 1678885403
19 1678885403
20 1678885403
21 1678885403
22 1678885403
23 1678885403
24 1678885403
25 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.day.singleton.ep; importar java.sql.Connection; importar java.sql.driverManager; importar java.sql.sqLexception; public enum myObject {conexão de conexão; "jdbc: mysql: // ...:/weChat_? useunicode = true & caracterEncoding = utf-"; string name = "root"; string senha = ""; string drivername = "com.mysql.jdbc.driver"; classe; {E.PrintStackTrace ();} Catch (sqLexception e) {e.printStackTrace ();}} conexão pública getConnection () {retornar conexão;}} Classe de thread
pacote com.weishiyao.learn.day.singleton.ep; public class mythread estende thread {@OverridePublic void run () {for (int i =; i <; i ++) {System.out.println (myObject.Connection.GetConnection (). Hashcode (); Executar aula
pacote com.weishiyao.learn.day.singleton.ep; public class Run {public static void main (string [] args) {mythread t = new mythread (); mythread t = new mythread (); mythread t = new myth (); mythread t = new mythread (); Mythread (); t.start (); t.start (); t.start (); t.start (); t.start (); t.start (); }} Resultados de execução
1 O construto myObject foi chamado
2 56823666
3 56823666
4 56823666
5 56823666
6 56823666
7 56823666
8 56823666
9 56823666
10 56823666
11 56823666
12 56823666
13 56823666
14 56823666
15 56823666
16 56823666
17 56823666
18 56823666
19 56823666
20 56823666
21 56823666
22 56823666
23 56823666
24 56823666
25 56823666
26 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.day.singleton.ep; importar java.sql.connection; importar java.sql.driverManager; import java.sql.sqLexception; public myObject {public enum) MyObject foi chamado "); string url =" jdbc: mysql: // ...:/weChat_? Useunicode = true & caracterencoding = utf- "; string name =" root "; string senha ="; password);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();}}public Connection getConnection() {return connection;}}public static Connection getConnection() {return MyEnumSingleton.connectionFactory.getConnection();}} Altere o código do thread
pacote com.weishiyao.learn.day.singleton.ep; public class mythread estende thread {@OverridePublic void run () {for (int i =; i <; i ++) {System.out.println (MyObject.getConnection (). Hashcode ()); resultado
1 O construto myObject foi chamado
2 1948356121
3 1948356121
4 1948356121
5 1948356121
6 1948356121
7 1948356121
8 1948356121
9 1948356121
10 1948356121
11 1948356121
12 1948356121
13 1948356121
14 1948356121
15 1948356121
16 1948356121
17 1948356121
18 1948356121
19 1948356121
20 1948356121
21 1948356121
22 1948356121
23 1948356121
24 1948356121
25 1948356121
26 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.