Java single interest mode and multi threaded summary

  • 2020-05-07 19:35:32
  • OfStack

concept:

The singleton pattern in java is a common design pattern, and there are three types of singleton patterns: lazy singleton, hungry singleton, and registered singleton.

The singleton pattern has the following characteristics:

1. The singleton class can only have one instance.

2. The 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 and that it instantiates itself and provides that 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. All of these applications are more or less a resource manager. Each computer can have several printers, but only one Printer Spooler, to avoid having two print jobs output to the printer at the same time. Each computer can have a number of communication ports, and the system should centrally manage these communication ports so that one communication port is not simultaneously invoked by two requests. In short, the choice of singleton mode is to avoid the state of non - 1, to avoid the government out of long.

Here mainly introduces two kinds in detail: lazy Chinese style and hungry Chinese style

1. Load now/hungrier

The instance is created before the method is called. The code:


package com.weishiyao.learn.day.singleton.ep;
public class MyObject {
//  Immediate loading mode == Villian mode 
private static MyObject myObject = new MyObject();
private MyObject() {
}
public static MyObject getInstance() {
//  This code version is loaded immediately 
//  The disadvantage of this version of the code is that there can be no other instance variables 
//  because getInstance() Method is not synchronized 
//  So it's possible to have a non-thread-safe problem 
return myObject;
}
}

creates the thread class


package com.weishiyao.learn.day.singleton.ep;
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
}

creates the 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();
}
}

The results

1 167772895
2 167772895
3 167772895

hashCode is the same value, indicating that the object is also the same, indicating that the immediate loading type of simple interest mode is implemented

2. Lazy loading/lazy

The instance will not be created until the method is called. The implementation scheme can be to put the instantiation into the no-argument constructor, so that the instance of the object will be created only when the method is called. The code:


package com.weishiyao.learn.day.singleton.ep;
public class MyObject {
private static MyObject myObject;
private MyObject() {
}
public static MyObject getInstance() {
//  Lazy loading 
if (myObject != null) {
} else {
myObject = new MyObject();
}
return myObject;
}
}

creates the thread class


package com.weishiyao.learn.day.singleton.ep;
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
} 

creates the run class


package com.weishiyao.learn.day8.singleton.ep2;
public class Run {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start();
}
} 

The results

1 167772895

This takes out an instance of an object, but in a multi-threaded environment, there are multiple instances, so it's not a singleton

runs 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();
}
}

The results

1 980258163
2 1224717057
3 1851889404
4 188820504
5 1672864109

Since there is a problem, to solve the problem, in lazy mode multi-threaded solution, code:

The first option, the most common, is to add synchronized, and synchronized can be added to different locations

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() {
//  Lazy loading 
try {
if (myObject != null) {
} else {
//  The simulation is done before the object is created 1 Some preparatory work 
Thread.sleep(); myObject = new MyObject(); }
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
} 

This synchronized synchronization scheme is so inefficient that the entire method is locked

the second synchronized use scheme


package com.weishiyao.learn.day.singleton.ep;
public class MyObject {
private static MyObject myObject;
private MyObject() {
}
public static MyObject getInstance() {
//  Lazy loading 
try {
synchronized (MyObject.class) {
if (myObject != null) {
} else {
//  The simulation is done before the object is created 1 Some preparatory work 
Thread.sleep();
myObject = new MyObject();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}

This method is very inefficient, all the code in the method is locked, only the key code needs to be locked, the third synchronized use scheme


package com.weishiyao.learn.day.singleton.ep;
public class MyObject {
private static MyObject myObject;
private MyObject() {
}
public static MyObject getInstance() {
//  Lazy loading 
try {
if (myObject != null) {
} else {
//  The simulation is done before the object is created 1 Some preparatory work 
Thread.sleep();
synchronized (MyObject.class) {
myObject = new MyObject();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
} 

This looks like an optimal solution, but after running 1, it turns out to be non-thread-safe

Results:

1 1224717057
2 971173439
3 1851889404
4 1224717057
5 1672864109
Why?

Although the statement of object creation is locked, only one thread can complete the creation at a time. However, after the first thread comes in to complete the Object object, the second thread can continue to create the Object object


package com.weishiyao.learn.day.singleton.ep;
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
}
0

You only need to add one more judgment to the lock to ensure the 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 the built-in static class to implement the singleton

The main code


package com.weishiyao.learn.day.singleton.ep;
public class MyObject {
//  Inner class mode 
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 {
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
}

runs the class


package com.weishiyao.learn.day.singleton.ep;
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
}
3

The results of

1851889404
1851889404
1851889404
1851889404
1851889404

The thread-safe singleton pattern is obtained through the internal static class

4. Serialization and deserialization singleton pattern

The built-in static classes can achieve thread-safety, but if you run into a serialized object, the result is multiple

MyObject code


package com.weishiyao.learn.day.singleton.ep;
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
}
4

business class


package com.weishiyao.learn.day.singleton.ep;
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
}
5

The results of

1 970928725
2 1099149023

Two different hashCode, proving that they are not the same object solution, add the following code


package com.weishiyao.learn.day.singleton.ep;
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
}
6

Called during deserialization, you get the same object

System.out.println(myObject.readResolve().hashCode());

The results of

1 1255301379
2 calls the readResolve method!
3 1255301379

Same hashCode, same object

5. Use the static code block to implement the singleton

The code in the static code block is already executing when the class is used, so you can use the static code fast feature to implement the single-interest pattern

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 {
@Override
public void run() {
for (int i = ; i < ; i++) {
System.out.println(MyObject.getInstance().hashCode());
}
}
}

runs the class


package com.weishiyao.learn.day.singleton.ep;
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
}
9

operation 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 mode is also successfully obtained by using the feature that static code blocks are executed only once

6. Use enum enumerated data types to implement the singleton pattern

Enumeration enum is similar to the static code block in that the constructor is called automatically when enumeration is used and can also be used to implement the singleton pattern

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(" Call the MyObject The structure of the ");
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 {
@Override
public void run() {
for (int i = ; i < ; i++) {
System.out.println(MyObject.connectionFactory.getConnection().hashCode());
}
}
}

run classes


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();
}
}

The results

1 calls the construction of 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

The above notation exposes the enumeration class as a violation of the "duty sheet 1" principle, and one class can be used 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(" Call the MyObject The structure of the ");
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();
}
}

changes the thread code


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());
}
}
} 

The results of

1 calls the construction of 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

The above summarizes the various situations and solutions encountered when the single-interest mode is combined with multi-threading for future reference.


Related articles: