Concept:
The singleton pattern in Java is a common design pattern. There are three types of singleton patterns: lazy-style singleton, hungry-style singleton, and registration-style singleton.
The singleton mode has the following characteristics:
1. A singleton class can only have one instance.
2. A singleton class must create its own unique instance.
3. The singleton class must provide this instance to all other objects.
The singleton pattern ensures that a class has only one instance, instantiates itself and provides this instance to the entire system. In computer systems, thread pools, caches, log objects, dialog boxes, printers, and graphics card driver objects are often designed as singletons. These applications all have more or less the functionality of resource managers. Each computer can have several printers, but there can only be one Printer Spooler to prevent two print jobs from being output to the printer at the same time. Each computer can have several communication ports, and the system should centrally manage these communication ports to prevent one communication port from being called by two requests at the same time. In short, the purpose of choosing the singleton mode is to avoid inconsistent states and avoid long-term policies.
Here we mainly introduce two types in detail: lazy Chinese style and hungry Chinese style
1. Immediate loading/hungry Chinese style
In calling Before the method, the instance has been created, 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; } }
Create thread class
package com.weishiyao.learn.day.singleton.ep; public class MyThread extends Thread { @Override public void run() { System.out.println(MyObject.getInstance().hashCode()); } }
Create running class
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(); } }
Run result
1 167772895
2 167772895
3 167772895
The hashCode is the same value, indicating that the object is also The same one, indicating the implementation of the immediate loading single-interest model
2. Lazy loading/lazy style
The instance will not be created until the method is called, implementation plan You can put the instantiation in the parameterless constructor, so that an instance of the object will be created only when called. Code:
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; } }
Create a thread class
package com.weishiyao.learn.day.singleton.ep; public class MyThread extends Thread { @Override public void run() { System.out.println(MyObject.getInstance().hashCode()); } }
Create running class
package com.weishiyao.learn.day8.singleton.ep2; public class Run { public static void main(String[] args) { MyThread t1 = new MyThread(); t1.start(); } }
##Run result
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 1851889404
4 188820504
5 1672864109
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; } }
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; } }
2 971173439
3 1851889404
4 1224717057
5 1672864109
Why?
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; } }
2 1224717057
3 1224717057
4 1224717057
5 1224717057
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(); } }
##Result
1851889404
1851889404
1851889404
1851889404
Thread-safe singleton mode is obtained through internal static classes
4. Serialization And deserialization singleton mode
Built-in static classes can achieve thread safety issues, but if you encounter a serialized object, the result obtained by using the default method is still multiple instances
MyObject Code
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; // } }
Business Class
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(); } } }
Result
1 970928725
Two different hashCode proves that they are not the same object. The solution is to add the following code
protected MyObject readResolve() { System.out.println("调用了readResolve方法!"); return MyObjectHandler.myObject; }
When called during deserialization, you can get the same object
System.out.println(myObject.readResolve().hashCode());
Result
1 1255301379
3 1255301379
The same hashCode proves that the same object is obtained
5. Use static code blocks to implement 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中文网!