Use of the singleton design mode and the design mode
Introduction
Singleton Pattern is one of the simplest Design Patterns in Java. This type of design mode belongs to the creation mode, which provides an optimal way to create objects.
This mode involves a single class, which is responsible for creating its own objects and 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.
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.
Intention: Ensure that a class has only one instance and provides a global access point to it.
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.
Solution: Determines whether the system already has this singleton. If yes, it returns the result. If no, it is created.
Key code: The constructor is private.
Application Instance: 1. One party can only have one chairman. 2. Windows is multi-process and multi-thread. When operating a file, it is inevitable that multiple processes or threads operate on a file simultaneously, therefore, all files must be processed through a unique instance. 3. Some device managers are often designed as Singleton mode. For example, if a computer has two printers, the same file cannot be printed by the two printers during output.
Advantages: 1. There is only one instance in the memory, which reduces the memory overhead, especially when instances are frequently created and destroyed (such as the cache on the homepage of the School of Management ). 2. Avoid multiple resource occupation (such as file write operations ).
Disadvantages: There is no interface, and it cannot be inherited. In conflict with the single responsibility principle, a class should only care about internal logic, rather than how to instantiate the outside.
Use Cases: 1. A unique serial number must be produced. 2. The counters in the WEB do not need to be added to the database every time they are refreshed. cache them in a single instance. 3. A created object consumes too many resources, such as connections between I/O and databases.
Notes: The Synchronous lock synchronized (Singleton. class) must be used in the getInstance () method to prevent the instance from being instantiated multiple times when multiple threads enter simultaneously.
Implementation methods of Singleton Mode
The Singleton mode can be implemented in multiple ways, as shown below:
1. The thread is not secure.
Whether to initialize Lazy: Yes
Multi-thread security: No
Implementation difficulty: Easy
Description: This is the most basic implementation method. The biggest problem with this implementation is that multithreading is not supported. Because synchronized is not locked, it is not considered a singleton mode strictly.
This lazy loading method is obvious, does not require thread security, and does not work properly in multithreading.
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 described in the following sections support multithreading, but the performance varies.
2. Lazy, thread security
Whether to initialize Lazy: Yes
Multi-thread security: Yes
Implementation difficulty: Easy
Description: This method has good lazy loading and can work well in multiple threads. However, the efficiency is very low. In 99% cases, synchronization is not required.
Advantage: initialization is performed for the first call to avoid Memory waste.
Disadvantage: synchronized must be locked to ensure the Singleton, but locking will affect the efficiency.
The performance of getInstance () is not critical to applications (this method is rarely used ).
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
Whether to initialize Lazy: No
Multi-thread security: Yes
Implementation difficulty: Easy
Description: This method is commonly used, but it is prone to spam objects.
Advantage: the execution efficiency is improved without locking.
Disadvantage: class initialization is a waste of memory.
It is based on the classloder mechanism to avoid multi-thread synchronization. However, instances are instantiated during class loading. Although there are many causes for class loading, in Singleton mode, most of them call the getInstance method, but it cannot be determined that other methods (or other static methods) cause class loading, at this time, the initialization of 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, that is, double-checked locking)
JDK version: from JDK
Whether to initialize Lazy: Yes
Multi-thread security: Yes
Implementation difficulty: complicated
Description: This method uses a double lock mechanism to ensure high performance in the case of multiple threads.
The performance of getInstance () is critical to applications.
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; } }
Note that volatile is added here after jdk5. this field is introduced because it supports unordered execution of the processor. Instantiate the address in the heap, which is not the same as the declared address.
5. Registration type/static internal class
Whether to initialize Lazy: Yes
Multi-thread security: Yes
Implementation difficulty: Average
Description: This method achieves the same effect as the double lock method, but it is easier to implement. This method should be used instead of the double check lock method to use delayed initialization for static domains. This method is only applicable to static domains. The double check lock method can be used when the instance domain needs to be delayed during initialization. This method also uses the classloder mechanism to ensure that there is only one thread during instance initialization. It is different from the 3rd method: 3rd methods as long as the Singleton class is loaded, then the instance will be instantiated (the lazy loading effect is not achieved), and this method is because the Singleton class is loaded, and the instance is not necessarily initialized. Because the SingletonHolder class is not actively used, the SingletonHolder class is explicitly loaded only when the getInstance method is explicitly called to instantiate the instance. Imagine that instantiating an instance consumes a lot of resources, so you want to delay loading. On the other hand, you do not want to instantiate the instance when loading the Singleton class, because the Singleton class cannot be actively used in other places and loaded, it is obviously inappropriate to instantiate the instance at this time. At this time, this method is more reasonable than the 3rd 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: from JDK
Whether to initialize Lazy: No
Multi-thread security: Yes
Implementation difficulty: Easy
Description: This implementation method has not been widely used yet, but it is the best way to implement the singleton mode. It is more concise and automatically supports serialization, which definitely prevents multiple instantiation.
This method is advocated by Josh Bloch, author of objective Java. It not only avoids multithreading synchronization, but also automatically supports serialization to prevent deserialization from re-creating new objects, it is absolutely prevented from being instantiated multiple times. However, since the enum feature was added only after JDK1.5, it is difficult to write in this way, and it is rarely used in actual work.
Private constructor methods cannot be called through reflection attack.
Code example:
public enum Singleton { INSTANCE; public void whateverMethod() { } }
Summary
Experience: Generally, we do not recommend 1st or 2nd lazy methods. We recommend that you use 3rd hunger. Only when lazy loading is implemented explicitly can 5th registration methods be used. If deserialization is involved in object creation, you can use 6th enumeration methods. If you have other special requirements, consider using 4th double-check locks.