What is singleton mode
This pattern involves a single class that is responsible for creating its own objects while ensuring that only a single object is created. This class provides a way to access its unique object, which can be accessed directly without instantiating the object of this class.
matters needing attention
- Singleton mode can only have one instance (only one object)
- The singleton class must create its own unique instance (create its own object inside the method)
- A singleton class must provide this instance to all other objects
main points
- Private construction method
The purpose of privatizing the constructor of this class is to prohibit other programs from creating objects of this class. At the same time, it is also to remind those who view the code that I am using singleton mode to prevent others from modifying it arbitrarily. - Private static reference to own instance
- Static common method with its own instance as the return value
Why are methods and references static
There are only two methods in the program call class- Create an object of a class and use it to call methods in the class
- Directly call the methods in the class through the class name
Because the singleton mode constructor is privatized, the method cannot be called through the first method, but only through the second method
The method called with the class name can only be static, and static methods cannot access non static member variables. Therefore, the instance variables customized by the class must also be static
What's the usage?
Application examples:
- It is multi-process and multi-threaded. When operating a file, it is inevitable that multiple processes or threads operate a file at the same time, so all files must be processed through a unique instance.
- Some device managers are often designed in singleton mode. For example, a computer has two printers, which must be processed when outputting. Two printers cannot print the same file.
Singleton mode implementation
- Create a singleton class
class SingleObject{ private static SingleObject instance = new SingleObject(); //Private static reference to own instance private SingleObject(){} //Private construction method public static SingleObject getInstance() { //Static common method with its own instance as the return value return instance; } }
- The only way to get a singleton class
public class Main { public static void main(String[] args) { SingleObject instance = SingleObject.getInstance(); //Get unique instances through static methods } }
The above single example is based on the hungry man style. What is the hungry man style? Continue to look down
Several implementation methods of singleton mode
1. Hungry Han style
**Thread safe: * * yes
Implementation mode
class SingleObject{ private static SingleObject instance = new SingleObject(); //Instantiate directly when defining private SingleObject(){} //Private construction method public static SingleObject getInstance() { //Static common method with its own instance as the return value return instance; } }
Based on the classloader mechanism, the synchronization problem of multithreading is avoided
**Advantages: * * thread safety can be realized without locking, and the efficiency becomes higher when it is safe
**Disadvantages: * * class is initialized when loaded, which wastes memory
2. Lazy threads are unsafe
**Thread safe: * * no
Implementation mode
class SingleObject{ private static SingleObject instance; //Do not instantiate when defining private SingleObject(){} public static SingleObject getInstance() { if (instance==null) { //If it has been instantiated, return directly instance = new SingleObject(); //There is no instance. Return after creating the instance } return instance; } }
Strictly speaking, it does not belong to singleton mode
Threads are unsafe and multithreading cannot work
3. Lazy thread safety
**Thread safe: * * yes
Implementation mode
class SingleObject{ private static SingleObject instance; private SingleObject(){} public static synchronized SingleObject getInstance() { //Directly add synchronized lock on instance if (instance==null) { instance = new SingleObject(); } return instance; } }
**Advantages: * * it is initialized only after the first call, which is memory friendly
**Disadvantages: * * the efficiency of synchronize lock is very low
4. Double check lock (DCL lazy type)
After JDK version 1.5
Thread safe: Yes
class SingleObject{ private static SingleObject instance; private SingleObject(){} public static SingleObject getInstance() { if (instance==null) { //First judge whether it is empty synchronized (SingleObject.class) { //If it is empty, lock it if (instance == null) { //This instance may be created by the thread between the time when it is judged to be empty and the time when it is locked, so it needs to be judged again instance = new SingleObject(); } } } return instance; } }
The granularity is reduced and the performance is improved in the thread safe lazy mode
However, in extreme cases, there will still be problems, because instance = new SingleObject(); It's not an atomic operation. It will be divided into three steps
- Allocate memory space
- Execution construction method
- Point the object to this space
Instruction rearrangement may occur, resulting in the execution of instructions in the order of 132. In extreme cases, thread A executes 13 methods. At this time, thread B enters the judgment of the outermost layer. At this time, because instance already has memory space, but instance has not been constructed, B will return an empty memory space
Therefore, volatile should be added before instance to avoid instruction rearrangement
class SingleObject{ private static volatile SingleObject instance; //Avoid instruction rearrangement private SingleObject(){} public static SingleObject getInstance() { if (instance==null) { synchronized (SingleObject.class) { if (instance == null) { instance = new SingleObject(); } } } return instance; } }
However, there is still a problem in this situation. If we use the only object instance obtained, use reflection to obtain the construction problem of this class, modify the permission of the constructor through setAccessible(true), and then create a new object through the constructor, two objects will be created
public class Main { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { SingleObject instance = SingleObject.getInstance(); Constructor<SingleObject> declaredConstructor = SingleObject.class.getDeclaredConstructor(); //Get constructor reflection declaredConstructor.setAccessible(true); //Authority violation SingleObject singleObject = declaredConstructor.newInstance(); //Create objects by reflection } }
If you judge by locking and flag, you will also decompile the variable name of flag for decoding
We enter the newInstance source code
You can see that enumeration types cannot be created by reflection
So here we recommend using enum to create the singleton pattern
enum
JDK version: jdk1 5 cases
Thread safety: Yes
enum SingleObject{ INSTANCE; public static SingleObject getInstance() { return INSTANCE; } }
This implementation has not been widely used, but it is the best way to implement singleton mode. It is more concise, automatically supports serialization mechanism and absolutely prevents multiple instantiations.
Cannot be instantiated by reflection
Reference articles
Singleton mode
[crazy God says Java] single example mode - 23 design pattern series
Singleton mode
What is singleton mode? What does singleton mode do? Why use singleton mode
Singleton mode
Why is the constructor private in singleton mode? Why is the class attribute pointing to its own instance static? Why is a class method that takes its own instance as the return value static?
Why are member functions in singleton mode static?