Concept :
Le modèle singleton est un modèle de conception courant en Java. Il existe trois types de modèles singleton : le singleton de style paresseux, le singleton de style affamé et le singleton de style d'enregistrement.
Le mode singleton a les caractéristiques suivantes :
1. Une classe singleton ne peut avoir qu'une seule instance.
2. Les classes Singleton doivent créer leur propre instance unique.
3. La classe singleton doit fournir cette instance à tous les autres objets.
Le modèle singleton garantit qu'une classe n'a qu'une seule instance, s'instancie et fournit cette instance à l'ensemble du système. Dans les systèmes informatiques, les pools de threads, les caches, les objets de journal, les boîtes de dialogue, les imprimantes et les objets pilotes de carte graphique sont souvent conçus comme des singletons. Ces applications disposent toutes plus ou moins des fonctionnalités de gestionnaires de ressources. Chaque ordinateur peut avoir plusieurs imprimantes, mais il ne peut y avoir qu'un seul spouleur d'imprimante pour empêcher que deux travaux d'impression ne soient envoyés simultanément sur l'imprimante. Chaque ordinateur peut avoir plusieurs ports de communication, et le système doit gérer ces ports de communication de manière centralisée pour empêcher qu'un port de communication soit appelé par deux requêtes en même temps. En bref, le but du choix du mode singleton est d'éviter les états incohérents et d'éviter les politiques à long terme.
Ici, nous présentons principalement deux types en détail : le style chinois paresseux et le style chinois affamé
1. Chargement immédiat/style chinois affamé
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; } }
package com.weishiyao.learn.day.singleton.ep; public class MyThread extends Thread { @Override public void run() { 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(); t.start(); t.start(); t.start(); } }
2 167772895
3 167772895
.
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; } }
package com.weishiyao.learn.day.singleton.ep; public class MyThread extends Thread { @Override public void run() { System.out.println(MyObject.getInstance().hashCode()); } }
package com.weishiyao.learn.day8.singleton.ep2; public class Run { public static void main(String[] args) { MyThread t1 = new MyThread(); t1.start(); } }
Résultat d'exécution
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(); } }
2 1224717057
3 18518894044 188820504
5 1672864109
Puisqu'il y a un problème, il faut le résoudre La solution multithread en mode paresseux, code :
Le premier. L'option, la plus courante, consiste à ajouter synchronisé, et synchronisé peut être ajouté à différents emplacements
La première option est le verrouillage de méthode
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; } }
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; } }
.
écrit comme ceci semble être la solution optimale, mais après avoir exécuté les résultats, j'ai découvert qu'il n'était en fait pas thread-safepackage 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 9711734393 1851889404
4 1224717057
Pourquoi ?
Bien que l'instruction de création d'objet soit verrouillée, un seul thread peut terminer la création à la fois. Cependant, lorsque le premier thread arrive pour créer l'objet Object, le deuxième thread peut toujours continuer. , parce que nous avons uniquement verrouillé l'instruction create, la solution à ce problème
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 12247170573 1224717057
4 1224717057
3. Utilisez des classes statiques intégrées pour implémenter des singletons
Code principal
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; } }
package com.weishiyao.learn.day.singleton.ep; public class MyThread extends Thread { @Override public void run() { 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(); } }
1851889404
18518894041851889404
1851889404
Le mode singleton thread-safe est obtenu grâce à des classes statiques internes
4. Mode singleton de sérialisation et de désérialisation
Les classes statiques intégrées peuvent poser des problèmes de sécurité des threads, mais si vous rencontrez un objet sérialisé, le résultat obtenu en utilisant la méthode par défaut est toujours Plusieurs instances de
Code MonObjet
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; // } }
package 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(); } } }
2 1099149023
Deux hashCode différents, prouvant qu'il ne s'agit pas du même objet Solution, ajoutez l'extrait de code suivant <🎜. >
est appelé lors de la désérialisation et vous pouvez obtenir le même objet
protected MyObject readResolve() { System.out.println("调用了readResolve方法!"); return MyObjectHandler.myObject; }
Result
1 12553013792 La méthode readResolve a été appelée !
3 1255301379
Le même hashCode prouve que le même objet est obtenu
5. Utilisez des blocs de code statiques pour implémenter des singletons
静态代码块中的代码在使用类的时候就已经执行了,所以可以应用静态代码快这个特性来实现单利模式
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中文网!