concept:
Singleton pattern in Java is a common design pattern. Singleton pattern is divided into three types: lazy singleton, hungry singleton, and registered singleton.
The singleton mode has the following characteristics:
1. There can only be one instance in a singleton class.
2. The singleton class must create its own unique instance.
3. The singleton class must provide this instance to all other objects.
Singleton pattern ensures that a class has only one instance, and instantiates it itself and provides this instance to the entire system. In computer systems, driver objects for thread pools, caches, log objects, dialog boxes, printers, and graphics cards are often designed as singletons. These applications have more or less the functionality of a resource manager. Each computer can have several printers, but only one Printer Spooler can be available to avoid two print jobs 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 avoid one communication port being called simultaneously by two requests. In short, choosing a singleton model is to avoid inconsistent states and avoid political bullishness.
Here are two types of introductions: lazy and hungry
1. Load immediately/hungry style
Before calling the method, the instance has been created, code:
package com.weishiyao.learn.day.singleton.ep;public class MyObject {// Loading method immediately ==Evil mode private static MyObject myObject = new MyObject();private MyObject() {}public static MyObject getInstance() {// This code version is loading immediately// The disadvantage of this version of the code is that there cannot be other instance variables// Because the getInstance() method is not synchronized// Therefore, non-thread-safe problems may occur return myObject;}} Create a thread class
package com.weishiyao.learn.day.singleton.ep;public class MyThread extends Thread {@Overridepublic void run() {System.out.println(MyObject.getInstance().hashCode());}} Create a run 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(); t.start();}} Running results
1 167772895
2 167772895
3 167772895
hashCode is the same value, which means that the object is also the same, which means that the instant loading mode is implemented.
2. Lazy loading/lazy
The instance will be created after the method is called. The implementation plan can be to put instantiation into the parameterless constructor, so that an instance of the object will be created only when the method is called. Code:
package com.weishiyao.learn.day.singleton.ep;public class MyObject {private static MyObject myObject;private MyObject() {}public static MyObject getInstance() {// Delay loading 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 {@Overridepublic void run() {System.out.println(MyObject.getInstance().hashCode());}} Create a run class
package com.weishiyao.learn.day8.singleton.ep2;public class Run {public static void main(String[] args) {MyThread t1 = new MyThread();t1.start();}} Running results
1 167772895
Although an instance of an object is taken, if it is in a multi-threaded environment, multiple instances will occur, which is not a singleton pattern
Run the test 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();MyThread t = new MyThread();MyThread t = new MyThread();t.start();t.start();t.start();t.start(); t.start(); t.start(); }} Running results
1 980258163
2 1224717057
3 1851889404
4 188820504
5 1672864109
Since there is a problem, we need to solve the problem. Multithreaded solution in lazy mode, code:
The first solution, most commonly, add synchronized, and synchronized can be added to different positions
The first method locks
package com.weishiyao.learn.day.singleton.ep;public class MyObject {private static MyObject myObject;private MyObject() {}synchronized public static MyObject getInstance() {// Delay loading try {if (myObject != null) {} else {// Simulate some preparation before creating an object Thread.sleep(); myObject = new MyObject(); }} catch (InterruptedException e) {e.printStackTrace();}return myObject;}} This synchronized synchronization scheme results in too inefficient and the entire method is locked
The second synchronized usage scheme
package com.weishiyao.learn.day.singleton.ep;public class MyObject {private static MyObject myObject;private MyObject() {}public static MyObject getInstance() {// Delay loading try {synchronized (MyObject.class) {if (myObject != null) {} else {// Simulate some preparation before creating an object Thread.sleep();myObject = new MyObject();}}} catch (InterruptedException e) {e.printStackTrace();}return myObject;}} This method is also very low-efficiency. All codes in the method are locked. You only need to lock the key code. The third synchronized usage plan
package com.weishiyao.learn.day.singleton.ep;public class MyObject {private static MyObject myObject;private MyObject() {}public static MyObject getInstance() {// Delay loading try {if (myObject != null) {} else {// Simulate some preparation before creating an object Thread.sleep();synchronized (MyObject.class) {myObject = new MyObject();}}} catch (InterruptedException e) {e.printStackTrace();}return myObject;}} This seems to be the best solution, but after running it, I found that it is actually non-thread-safe
result:
1 1224717057
2 971173439
3 1851889404
4 1224717057
5 1672864109
Why?
Although the statement that creates an object is locked, only one thread can complete the creation at a time, after the first thread comes in to create the Object object, the second thread can still continue to create it, because we only lock the creation statement, this problem solution
package com.weishiyao.learn.day.singleton.ep;public class MyObject {private static MyObject myObject;private MyObject() {}public static MyObject getInstance() {// Delay loading try {if (myObject != null) {} else {// Simulate some preparation work before creating an object Thread.sleep();synchronized (MyObject.class) {if (myObject == null) {myObject = new MyObject();}}}} catch (InterruptedException e) {e.printStackTrace();}return myObject;}} Just add another judgment to the lock to ensure a singleton. This is the DCL double check mechanism
The results are as follows:
1 1224717057
2 1224717057
3 1224717057
4 1224717057
5 1224717057
3. Use built-in static classes to implement single cases
Main code
package com.weishiyao.learn.day.singleton.ep;public class MyObject {// Inner class method private static class MyObjectHandler {private static MyObject myObject = new MyObject();}public MyObject() {}public static MyObject getInstance() {return MyObjectHandler.myObject;}} Thread class code
package com.weishiyao.learn.day.singleton.ep;public class MyThread extends Thread {@Overridepublic void run() {System.out.println(MyObject.getInstance().hashCode());}} Run 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();MyThread t = new MyThread();MyThread t = new MyThread();t.start();t.start();t.start();t.start(); t.start(); t.start(); }} result
1851889404
1851889404
1851889404
1851889404
1851889404
Through internal static classes, a thread-safe singleton pattern is obtained
IV. Serialize and deserialize singleton patterns
Built-in static classes can achieve thread safety problems, but if you encounter serialized objects, the result obtained by using the default method is still multiple cases.
MyObject Code
package com.weishiyao.learn.day8.singleton.ep5;import java.io.Serializable;public class MyObject implements Serializable {/*** */private static final long serialVersionUID = 888L;// Internal class method 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("The readResolve method was called!");// return MyObjectHandler.myObject;// }} Business
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
2 1099149023
Two different hashCodes prove that they are not the same object. Solution, add the following code
protected MyObject readResolve() {System.out.println("The readResolve method was called!");return MyObjectHandler.myObject;} Called during deserialization, you can get the same object
System.out.println(myObject.readResolve().hashCode());
result
1 1255301379
2 The readResolve method was called!
3 1255301379
The same hashCode proves that the same object is obtained
5. Use static code blocks to implement single case
The code in the static code block is already executed when using the class, so the feature of static code fast can be used to implement the simple profit mode.
MyObject class
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;}} Thread class
package com.weishiyao.learn.day.singleton.ep;public class MyThread extends Thread {@Overridepublic void run() {for (int i = ; i < ; i++) {System.out.println(MyObject.getInstance().hashCode());}}} Run 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();MyThread t = new MyThread();MyThread t = new MyThread();t.start();t.start();t.start();t.start(); t.start(); t.start(); }} Running results:
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
The thread-safe singleton pattern is successfully obtained through the feature of only executing static code blocks once.
6. Use enum enum data types to implement singleton mode
The characteristics of enum enum and static code blocks are similar. When using enums, the constructor will be called automatically and can also be used to implement singleton mode.
MyObject class
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("The construct of MyObject was called");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;}} Thread class
package com.weishiyao.learn.day.singleton.ep;public class MyThread extends Thread {@Overridepublic void run() {for (int i = ; i < ; i++) {System.out.println(MyObject.connectionFactory.getConnection().hashCode());}}} Run 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();MyThread t = new MyThread();MyThread t = new MyThread();t.start();t.start();t.start();t.start(); t.start(); t.start(); }} Running results
1 The MyObject construct was called
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
The above writing method exposes the enumeration class, which violates the "single responsibility principle". You can use a class to wrap the enumeration.
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("The construct of MyObject was called");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();}} Change the thread code
package com.weishiyao.learn.day.singleton.ep;public class MyThread extends Thread {@Overridepublic void run() {for (int i = ; i < ; i++) {System.out.println(MyObject.getConnection().hashCode());}}} result
1 The MyObject construct was called
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
The above summarizes various situations and solutions encountered when combining the single-interest mode with multi-threading, so that it can be reviewed when used later.