Creator mode - singleton mode
The main focus of creative mode is "how to create objects?", Its main feature is "separating the creation and use of objects".
This can reduce the coupling degree of the system, and users do not need to pay attention to the creation details of objects.
The creation mode is divided into:
- Singleton mode
- Factory method model
- Abstract engineering pattern
- Prototype mode
- Builder pattern
1.1 single case design mode
Singleton Pattern is one of the simplest design patterns in Java. This type of design pattern is a creation pattern, which provides the best 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 object, which can be accessed directly without instantiating the object of this class.
1.1.1 structure of singleton mode
The main roles of singleton mode are as follows:
- Single class. Only one instance of a class can be created
- Access class. Using singleton classes
1.1.2 implementation of singleton mode
There are two types of singleton design patterns:
Hungry Chinese style: class loading will cause the single instance object to be created
Lazy: class loading does not cause the single instance object to be created, but only when the object is used for the first time
/** * Evil Han style * Create this type of object in a static code block */ public class Singleton { //Private construction method private Singleton() {} //Create an object of this class at the member location private static Singleton instance; static { instance = new Singleton(); } //Provide a static method to get the object public static Singleton getInstance() { return instance; } }
explain:
In this way, a static variable of Singleton type is declared at the member position, and the object is created in the static code block and for the loading of the class. Therefore, it is basically the same as hungry man mode 1. Of course, this mode also has the problem of memory waste.
2 hungry Chinese - mode 2 (static code block mode)
/** * Hungry Han style * Create this type of object in a static code block */ public class Singleton { //Private construction method private Singleton() {} //Create an object of this class at the member location private static Singleton instance; static { instance = new Singleton(); } //Provide a static method to get the object public static Singleton getInstance() { return instance; } }
explain:
In this way, a static variable of Singleton type is declared at the member position, and the object is created in the static code block and for the loading of the class. Therefore, it is basically the same as hungry man mode 1. Of course, this mode also has the problem of memory waste.
3 lazy - mode 1 (thread unsafe)
/** * Lazy style * Thread unsafe */ public class Singleton { //Private construction method private Singleton() {} //Create an object of this class at the member location private static Singleton instance; //Provide a static method to get the object public static Singleton getInstance() { if(instance == null) { instance = new Singleton(); } return instance; } }
explain:
From the above code, we can see that this method declares a static variable of Singleton type at the member position, and does not assign an object. When did the assignment take place? The Singleton class object is created only when the getInstance() method is called to obtain the Singleton class object, which realizes the effect of lazy loading. However, if it is a multithreaded environment, thread safety problems will occur.
4 lazy - mode 2 (thread safe)
/** * Lazy style * Thread safety */ public class Singleton { //Private construction method private Singleton() {} //Create an object of this class at the member location private static Singleton instance; //Provide a static method to get the object public static synchronized Singleton getInstance() { if(instance == null) { instance = new Singleton(); } return instance; } }
explain:
This method also realizes the effect of lazy loading and solves the problem of thread safety. However, the synchronized keyword is added to the getInstance() method, resulting in a particularly low execution effect of this method. From the above code, we can see that the thread safety problem only occurs when initializing instance. Once the initialization is completed, it does not exist.
Lazy - mode 3 (double check lock)
Let's talk about locking in lazy mode. For getInstance() method, most operations are read operations, which are thread safe. Therefore, we don't have to make each thread hold a lock to call this method. We need to adjust the timing of locking. This also produces a new implementation mode: double check lock mode
/** * Double check mode */ public class Singleton { //Private construction method private Singleton() {} private static Singleton instance; //Provide a static method to get the object public static Singleton getInstance() { //First judgment, if instance Not for null,Instead of entering the lock grabbing stage, return to the instance directly if(instance == null) { synchronized (Singleton.class) { //After grabbing the lock, judge again whether it is null if(instance == null) { instance = new Singleton(); } } } return instance; } }
5 lazy - mode 3 (double check lock)
Let's talk about locking in lazy mode. For getInstance() method, most operations are read operations, which are thread safe. Therefore, we don't have to make each thread hold a lock to call this method. We need to adjust the timing of locking. This also produces a new implementation mode: double check lock mode
/** * Double check mode */ public class Singleton { //Private construction method private Singleton() {} private static Singleton instance; //Provide a static method to get the object public static Singleton getInstance() { //First judgment, if instance Not for null,Instead of entering the lock grabbing stage, return to the instance directly if(instance == null) { synchronized (Singleton.class) { //After grabbing the lock, judge again whether it is null if(instance == null) { instance = new Singleton(); } } } return instance; } }
Double check lock mode is a very good singleton implementation mode, which solves the problems of singleton, performance and thread safety. The above double check lock mode looks perfect, but it is actually a problem. In the case of multithreading, null pointer problems may occur. The reason for the problem is that the JVM will optimize and reorder instructions when instantiating objects.
To solve the problem of null pointer exception caused by double check lock mode, you only need to use volatile keyword, which can ensure visibility and order.
/** * Double check mode */ public class Singleton { //Private construction method private Singleton() {} private static volatile Singleton instance; //Provide a static method to get the object public static Singleton getInstance() { //First judgment, if instance Not for null,Instead of entering the lock grabbing stage, return to the actual situation directly if(instance == null) { synchronized (Singleton.class) { //After grabbing the lock, judge whether it is empty again if(instance == null) { instance = new Singleton(); } } } return instance; } }
Summary:
The double check lock mode after adding volatile keyword is a better singleton implementation mode, which can ensure thread safety and no performance problems in the case of multithreading.
- Lazy - mode 4 (static inner class mode)
In the static internal class singleton mode, the instance is created by the internal class. Because the JVM will not load the static internal class in the process of loading the external class, it will be loaded only when the properties / methods of the internal class are called, and its static properties will be initialized. Because static attributes are modified by static, they are guaranteed to be instantiated only once, and the instantiation order is strictly guaranteed.
/** * Static internal class mode */ public class Singleton { //Private construction method private Singleton() {} private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } //Provide a static method to get the object public static Singleton getInstance() { return SingletonHolder.INSTANCE; } }
explain:
The INSTANCE will not be initialized when the Singleton class is loaded for the first time. Only getInstance is called for the first time, and the virtual machine loads SingletonHolder
And initialize INSTANCE, which can not only ensure thread safety, but also ensure the uniqueness of Singleton class.
Summary:
Static inner class singleton mode is an excellent singleton mode, which is commonly used in open source projects. Without any lock, it ensures the safety of multithreading without any performance impact and waste of space.
- Enumeration mode
Enumeration class implementation singleton mode is the highly recommended singleton implementation mode, because the enumeration type is thread safe and can only be loaded once. The designer makes full use of this feature of enumeration to realize the singleton mode. The writing method of enumeration is very simple, and the enumeration type is the only singleton implementation mode that will not be destroyed.
/** * Enumeration mode */ public enum Singleton { INSTANCE; }
explain:
The enumeration method belongs to the evil Chinese style.