Singleton pattern
Singleton Pattern is one of the simplest design patterns in Java. This type of design pattern is a creational pattern, which provides an optimal way to create objects.
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 objects directly, without the need to instantiate an object of the class.
Note:
1. A 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.
Introduction
Intent: Ensure that a class has only one instance and provide an access method to it Global access point.
Main solution: A globally used class is frequently created and destroyed.
When to use: When you want to control the number of instances and save system resources.
How to solve: Determine whether the system already has this singleton, if so, return it, if not, create it.
Key code: The constructor is private.
Application examples: 1. A party can only have one chairman. 2. Windows 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. Therefore, all file processing must be performed through a unique instance. 3. Some device managers are often designed in singleton mode. For example, if a computer has two printers, it must be processed when outputting that two printers cannot print the same file.
Advantages: 1. There is only one instance in the memory, which reduces memory overhead, especially when instances are frequently created and destroyed (such as the School of Management homepage page cache). 2. Avoid multiple occupation of resources (such as file writing operations).
Disadvantages: There is no interface and cannot be inherited, which conflicts with the single responsibility principle. A class should only care about the internal logic and not how to instantiate it outside.
Usage scenarios: 1. Require the production of a unique serial number. 2. The counter in the WEB does not need to be added to the database every time it is refreshed. It is cached first with a single instance. 3. An object created consumes too many resources, such as I/O and database connections.
Note: The synchronization lock synchronized (Singleton.class) needs to be used in the getInstance() method to prevent multiple threads from entering at the same time and causing the instance to be instantiated multiple times.
Implementation
We will create a SingleObject class. SingleObject The class has its private constructor and a static instance of itself.
SingleObject The class provides a static method for the outside world to obtain its static instance. SingletonPatternDemo, our demo class uses the SingleObject class to obtain the SingleObject object.
Step 1
Create a Singleton class.
SingleObject.java
public class SingleObject { //创建 SingleObject 的一个对象 private static SingleObject instance = new SingleObject(); //让构造函数为 private,这样该类就不会被实例化 private SingleObject(){} //获取唯一可用的对象 public static SingleObject getInstance(){ return instance; } public void showMessage(){ System.out.println("Hello World!"); } }
Step 2
Get the unique object from the singleton class.
SingletonPatternDemo.java
public class SingletonPatternDemo { public static void main(String[] args) { //不合法的构造函数 //编译时错误:构造函数 SingleObject() 是不可见的 //SingleObject object = new SingleObject(); //获取唯一可用的对象 SingleObject object = SingleObject.getInstance(); //显示消息 object.showMessage(); } }
Step 3
Verify the output.
Hello World!
Several ways to implement the singleton mode
There are many ways to implement the singleton mode, as follows:
1. Lazy style, thread unsafe
Whether Lazy initialization: Yes
Whether it is multi-thread safe: No
Difficulty of implementation: Easy
Description: This method is the most basic implementation method. The biggest problem with this implementation is that it does not support multi-threading. Because there is no synchronized lock, it is not considered a singleton mode in a strict sense.
This method of lazy loading obviously does not require thread safety and cannot work properly in multi-threads.
Code example:
public class Singleton { private static Singleton instance; private Singleton (){} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
The implementation methods introduced next all support multi-threading, but in performance There is a difference.
2. Lazy style, thread safety
Whether Lazy initialization: Yes
Whether multi-thread safety: Yes
Difficulty of implementation:Easy
Description:This method has good lazy loading and can work well in multi-threads , however, the efficiency is very low, and synchronization is not needed in 99% of cases.
Advantages: It is initialized only after the first call to avoid memory waste.
Disadvantages: synchronized must be locked to ensure singleton, but locking will affect efficiency.
The performance of getInstance() is not critical to the application (the method is used less frequently).
Code example:
public class Singleton { private static Singleton instance; private Singleton (){} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
3. Hungry Chinese style
Whether Lazy initialization:No
Is it multi-thread safe: Yes
Difficulty of implementation: Easy
Description: This method is more commonly used, but it is easy to generate garbage objects.
Advantages: No locking, execution efficiency will be improved.
Disadvantages: The class is initialized when it is loaded, which wastes memory.
It avoids multi-thread synchronization problems based on the classloder mechanism. However, instance is instantiated when the class is loaded. Although there are many reasons for class loading, most of them call the getInstance method in the singleton mode, but It is also not certain that there are other ways (or other static methods) that cause class loading. At this time, initializing the instance obviously does not achieve the lazy loading effect.
Code example:
public class Singleton { private static Singleton instance = new Singleton(); private Singleton (){} public static Singleton getInstance() { return instance; } }
4. Double check lock/double check lock (DCL, double-checked locking)
JDK version: JDK1.5 onwards
Whether Lazy initialization: Yes
Whether it is multi-thread safe: Yes
Difficulty of implementation: More complex
Description:This method is used Double lock mechanism, safe and able to maintain high performance in multi-threaded situations.
The performance of getInstance() is critical to the application.
Code example:
public class Singleton { private volatile static Singleton singleton; private Singleton (){} public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
5. Registered/static inner class
Whether it is Lazy Initialization: Yes
Is it multi-thread safe: Yes
Difficulty of implementation: General
Description : This method can achieve the same effect as the double check lock method, but the implementation is simpler. Use lazy initialization for static fields. This method should be used instead of the double-check lock method. This method is only applicable to static domains. The double-check lock method can be used when the instance domain requires delayed initialization.
This method also uses the classloder mechanism to ensure that there is only one thread when initializing the instance. It is different from the third method: in the third method, as long as the Singleton class is loaded, the instance will be instantiated (no To achieve lazy loading effect), in this way, the Singleton class is loaded and the instance is not necessarily initialized. Because the SingletonHolder class is not actively used, the SingletonHolder class will only be explicitly loaded by calling the getInstance method to instantiate the instance. Imagine if instantiating an instance consumes resources, so you want it to be loaded lazily. On the other hand, you don't want to instantiate it when the Singleton class is loaded, because there is no guarantee that the Singleton class may be actively used in other places and thus be Loading, then it is obviously inappropriate to instantiate instance at this time. At this time, this method seems very reasonable compared to the third method.
Code example:
public class Singleton { private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } }
6, enumeration
JDK version: Starting from JDK1.5
Whether Lazy initialization:No
Whether it is multi-thread safe:Yes
Difficulty of implementation : Yi
Description: This implementation has not been widely adopted, but it is the best way to implement the singleton pattern. It is more concise, automatically supports the serialization mechanism, and absolutely prevents multiple instantiations.
This method is advocated by Effective Java author Josh Bloch. It not only avoids multi-thread synchronization problems, but also automatically supports the serialization mechanism to prevent deserialization from re-creating new objects and absolutely prevents multiple instantiations. However, since the enum feature was only added after JDK1.5, writing in this way makes people feel unfamiliar, and it is rarely used in actual work.
Private constructors cannot be called through reflection attack.
Code example:
public enum Singleton { INSTANCE; public void whateverMethod() { } }
Experience:Under normal circumstances, it is not recommended to use the 1st and 2nd lazy man methods, and it is recommended to use the 3rd hungry man method. The fifth registration method will only be used when the lazy loading effect is explicitly implemented. If it involves deserialization to create objects, you can try the sixth enumeration method. If you have other special needs, you can consider using the fourth double check lock method.