Konzept:
Das Singleton-Muster ist ein gängiges Entwurfsmuster in Java. Es gibt drei Arten von Singleton-Mustern: Singleton im Lazy-Stil, Singleton im Hungrig-Stil und Singleton im Registrierungs-Stil.
Das Singleton-Modell weist die folgenden Eigenschaften auf:
1. Eine Singleton-Klasse kann nur eine Instanz haben.
2. Singleton-Klassen müssen ihre eigene eindeutige Instanz erstellen.
3. Die Singleton-Klasse muss diese Instanz allen anderen Objekten bereitstellen.
Das Singleton-Muster stellt sicher, dass eine Klasse nur eine Instanz hat, sich selbst instanziiert und diese Instanz dem gesamten System zur Verfügung stellt. In Computersystemen werden Thread-Pools, Caches, Protokollobjekte, Dialogfelder, Drucker und Grafikkartentreiberobjekte häufig als Singletons konzipiert. Diese Anwendungen verfügen alle mehr oder weniger über die Funktionalität von Ressourcenmanagern. Jeder Computer kann über mehrere Drucker verfügen, es kann jedoch nur ein Druckerspooler vorhanden sein, um zu verhindern, dass zwei Druckaufträge gleichzeitig auf dem Drucker ausgegeben werden. Jeder Computer kann über mehrere Kommunikationsanschlüsse verfügen. Das System sollte diese Kommunikationsanschlüsse zentral verwalten, um zu verhindern, dass ein Kommunikationsanschluss gleichzeitig von zwei Anforderungen aufgerufen wird. Kurz gesagt besteht der Zweck der Wahl des Singleton-Modus darin, inkonsistente Zustände und langfristige Richtlinien zu vermeiden.
Hier stellen wir hauptsächlich zwei Typen im Detail vor: Lazy Chinese Style und Hungry Chinese Style
1. Sofortiges Laden/Hungry Chinese Style
In Aufruf Bevor die Methode erstellt wurde, wird die Instanz erstellt, Code:
package com.weishiyao.learn.day.singleton.ep; public class MyObject { // 立即加载方式==恶汉模式 private static MyObject myObject = new MyObject(); private MyObject() { } public static MyObject getInstance() { // 此代码版本为立即加载 // 此版本代码的缺点是不能有其他实例变量 // 因为getInstance()方法没有同步 // 所以有可能出现非线程安全的问题 return myObject; } }
Thread-Klasse erstellen
package com.weishiyao.learn.day.singleton.ep; public class MyThread extends Thread { @Override public void run() { System.out.println(MyObject.getInstance().hashCode()); } }
Lauf erstellen Klasse
package 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(); } }
Laufergebnis
1 167772895
2 167772895
3 167772895
hashCode ist derselbe Ein Wert zeigt an, dass das Objekt ebenfalls dasselbe ist, was darauf hinweist, dass der Single-Interest-Modus für sofortiges Laden implementiert wurde
2. Verzögertes Laden/Lazy-Stil
Die Instanz wird erst geladen, wenn die Methode aufgerufen wird. Die Implementierungslösung kann darin bestehen, die Instanziierung in den parameterlosen Konstruktor einzufügen, sodass die Instanz des Objekts nur erstellt wird, wenn sie aufgerufen wird
package com.weishiyao.learn.day.singleton.ep; public class MyObject { private static MyObject myObject; private MyObject() { } public static MyObject getInstance() { // 延迟加载 if (myObject != null) { } else { myObject = new MyObject(); } return myObject; } }Thread-Klasse erstellen
package com.weishiyao.learn.day.singleton.ep; public class MyThread extends Thread { @Override public void run() { System.out.println(MyObject.getInstance().hashCode()); } }Laufklasse erstellen
package com.weishiyao.learn.day8.singleton.ep2; public class Run { public static void main(String[] args) { MyThread t1 = new MyThread(); t1.start(); } }
Laufendes Ergebnis
package 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(); MyThread t = new MyThread(); MyThread t = new MyThread(); t.start(); t.start(); t.start(); t.start(); t.start(); } }1 980258163
2 1224717057
3 18518894044 188820504
5 1672864109
Da es ein Problem gibt, müssen wir es im Lazy-Modus lösen, Code:
Der erste Die häufigste Option besteht darin, synchronisiert hinzuzufügen, und synchronisiert kann an verschiedenen Orten hinzugefügt werden
Die erste Option ist die Methodensperre
package com.weishiyao.learn.day.singleton.ep; public class MyObject { private static MyObject myObject; private MyObject() { } synchronized public static MyObject getInstance() { // 延迟加载 try { if (myObject != null) { } else { // 模拟在创建对象之前做一些准备性的工作 Thread.sleep(); myObject = new MyObject(); } } catch (InterruptedException e) { e.printStackTrace(); } return myObject; } }Das zweite synchronisierte Nutzungsschema
package com.weishiyao.learn.day.singleton.ep; public class MyObject { private static MyObject myObject; private MyObject() { } public static MyObject getInstance() { // 延迟加载 try { synchronized (MyObject.class) { if (myObject != null) { } else { // 模拟在创建对象之前做一些准备性的工作 Thread.sleep(); myObject = new MyObject(); } } } catch (InterruptedException e) { e.printStackTrace(); } return myObject; } }>
so geschrieben scheint die optimale Lösung zu sein, aber nachdem ich die Ergebnisse ausgeführt hatte, stellte ich fest, dass es tatsächlich nicht threadsicher ist
Ergebnisse:package com.weishiyao.learn.day.singleton.ep; public class MyObject { private static MyObject myObject; private MyObject() { } public static MyObject getInstance() { // 延迟加载 try { if (myObject != null) { } else { // 模拟在创建对象之前做一些准备性的工作 Thread.sleep(); synchronized (MyObject.class) { myObject = new MyObject(); } } } catch (InterruptedException e) { e.printStackTrace(); } return myObject; } }1 1224717057
2 971173439
3 18518894044 1224717057
5 1672864109
nur ein weiteres Urteil in die Sperre eingefügt werden. Singleton kann garantiert werden . Dies ist der DCL-Doppelprüfmechanismus
package com.weishiyao.learn.day.singleton.ep; public class MyObject { private static MyObject myObject; private MyObject() { } public static MyObject getInstance() { // 延迟加载 try { if (myObject != null) { } else { // 模拟在创建对象之前做一些准备性的工作 Thread.sleep(); synchronized (MyObject.class) { if (myObject == null) { myObject = new MyObject(); } } } } catch (InterruptedException e) { e.printStackTrace(); } return myObject; } }1 1224717057
2 1224717057
3 12247170574 1224717057
5 1224717057
3. Verwenden Sie integrierte statische Klassen, um Singletons zu implementieren
Hauptcode
Thread-Klassencode
package com.weishiyao.learn.day.singleton.ep; public class MyObject { // 内部类方式 private static class MyObjectHandler { private static MyObject myObject = new MyObject(); } public MyObject() { } public static MyObject getInstance() { return MyObjectHandler.myObject; } }
Klasse ausführen
package com.weishiyao.learn.day.singleton.ep; public class MyThread extends Thread { @Override public void run() { System.out.println(MyObject.getInstance().hashCode()); } }
Ergebnis
1851889404package 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(); MyThread t = new MyThread(); MyThread t = new MyThread(); t.start(); t.start(); t.start(); t.start(); t.start(); } }1851889404
1851889404
18518894041851889404
Thread-sicherer Singleton-Modus wird durch interne statische Klassen erreicht
Eingebaute statische Klassen können Thread-Sicherheitsprobleme verursachen, aber wenn Sie auf ein serialisiertes Objekt stoßen, ist das durch die Verwendung der Standardmethode erhaltene Ergebnis immer noch Mehrere Instanzen von
Business Class
package com.weishiyao.learn.day8.singleton.ep5; import java.io.Serializable; public class MyObject implements Serializable { /** * */ private static final long serialVersionUID = 888L; // 内部类方式 private static class MyObjectHandler { private static MyObject myObject = new MyObject(); } public MyObject() { } public static MyObject getInstance() { return MyObjectHandler.myObject; } // protected MyObject readResolve() { // System.out.println("调用了readResolve方法!"); // return MyObjectHandler.myObject; // } }Ergebnis
1 970928725
2 1099149023package com.weishiyao.learn.day.singleton.ep; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class SaveAndRead { public static void main(String[] args) { try { MyObject myObject = MyObject.getInstance(); FileOutputStream fosRef = new FileOutputStream(new 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; try { fisRef = new FileInputStream(new File("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(); } } }
Zwei verschiedene HashCodes, die beweisen, dass es sich nicht um dasselbe Objekt handelt. Fügen Sie zur Lösung den folgenden Codeausschnitt hinzu
wird während der Deserialisierung aufgerufen und Sie können das gleiche Objekt erhalten
System.out.println (myObject.readResolve( ).hashCode());
protected MyObject readResolve() { System.out.println("调用了readResolve方法!"); return MyObjectHandler.myObject; }Ergebnis
1 1255301379
2 Die readResolve-Methode wurde aufgerufen!3 1255301379
5. Verwenden Sie statische Codeblöcke, um Singletons zu implementieren
静态代码块中的代码在使用类的时候就已经执行了,所以可以应用静态代码快这个特性来实现单利模式
MyObject类
package com.weishiyao.learn.day.singleton.ep; public class MyObject { private static MyObject instance = null; private MyObject() { super(); } static { instance = new MyObject(); } public static MyObject getInstance() { return instance; } }
线程类
package com.weishiyao.learn.day.singleton.ep; public class MyThread extends Thread { @Override public void run() { for (int i = ; i < ; i++) { System.out.println(MyObject.getInstance().hashCode()); } } }
运行类
package 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(); MyThread t = new MyThread(); MyThread t = new MyThread(); t.start(); t.start(); t.start(); t.start(); t.start(); } }
运行结果:
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
通过静态代码块只执行一次的特性也成功的得到了线程安全的单例模式
六、使用enum枚举数据类型实现单例模式
枚举enum和静态代码块的特性类似,在使用枚举时,构造方法会被自动调用,也可以用来实现单例模式
MyObject类
package com.weishiyao.learn.day.singleton.ep; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public enum MyObject { connectionFactory; private Connection connection; private MyObject() { try { System.out.println("调用了MyObject的构造"); String url = "jdbc:mysql://...:/wechat_?useUnicode=true&characterEncoding=UTF-"; String name = "root"; String password = ""; String driverName = "com.mysql.jdbc.Driver"; Class.forName(driverName); connection = DriverManager.getConnection(url, name, password); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } public Connection getConnection() { return connection; } }
线程类
package com.weishiyao.learn.day.singleton.ep; public class MyThread extends Thread { @Override public void run() { for (int i = ; i < ; i++) { System.out.println(MyObject.connectionFactory.getConnection().hashCode()); } } }
运行类
package 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(); MyThread t = new MyThread(); MyThread t = new MyThread(); t.start(); t.start(); t.start(); t.start(); t.start(); } }
运行结果
1 调用了MyObject的构造
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
上面这种写法将枚举类暴露了,违反了“职责单一原则”,可以使用一个类将枚举包裹起来
package com.weishiyao.learn.day.singleton.ep; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class MyObject { public enum MyEnumSingleton { connectionFactory; private Connection connection; private MyEnumSingleton() { try { System.out.println("调用了MyObject的构造"); String url = "jdbc:mysql://...:/wechat_?useUnicode=true&characterEncoding=UTF-"; String name = "root"; String password = ""; String driverName = "com.mysql.jdbc.Driver"; Class.forName(driverName); connection = DriverManager.getConnection(url, name, password); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } public Connection getConnection() { return connection; } } public static Connection getConnection() { return MyEnumSingleton.connectionFactory.getConnection(); } }
更改线程代码
package com.weishiyao.learn.day.singleton.ep; public class MyThread extends Thread { @Override public void run() { for (int i = ; i < ; i++) { System.out.println(MyObject.getConnection().hashCode()); } } }
结果
1 调用了MyObject的构造
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
以上总结了单利模式与多线程结合时遇到的各种情况和解决方案,以供以后使用时查阅。
更多Java单利模式与多线程总结归纳相关文章请关注PHP中文网!