introduce
Among java interview questions, the handwritten singleton pattern is an interview question with a relatively high hit rate. Therefore, we must be proficient in it. In fact, it is not difficult, it depends on whether you have mastered the principles. In fact, when I first came into contact with java programming, I memorized this singleton pattern more by rote. You have to memorize it every time you interview. Thinking about it now, it's embarrassing. If there is anything unclear about this singleton pattern, I hope this blog can help you.
Several common implementations
hungry man mode
principle
Because the initialization is realized when the class loading is completed, it is completed by the virtual machine, and there is no multi-threading problem at all. There is no multi-threaded competition at this time.
advantage
The code is simple to write and easy to understand. high speed.
shortcoming
If it is a relatively large object, it will always occupy the server memory from the time the class is loaded. It is possible that this object will not need to be created until the server has been running for a long time. Then this period of time is occupying the memory in vain. And reflection can brute force private constructors.
code display
/** * @author : echo_Huang Shi * @description: hungry man mode * @date : 2023/2/6 16:40 */ public class Hungry { //Static familiarity, initialization when class loading, avoiding the problem of multi-thread initialization private static Hungry hungry=new Hungry(); //private construct private Hungry(){} //public method to get instance public static Hungry getHungryEntity(){ return hungry; } /** * 50 Thread simulation Multi-threaded environment * @param args */ public static void main(String[] args) { for (int i=0;i<50;i++){ Thread thread=new Thread(){ @Override public void run() { System.out.println("Get a singleton instance: "+getHungryEntity()); } }; thread.start(); } } }
screenshot verification
lazy mode
principle
It is initialized when the client calls it. Use the method of synchronous code block to ensure that only one instance is initialized
advantage
Compared to Hungry Mode, it will only be loaded when called. The performance of the server will be relatively improved.
shortcoming
The code is slightly more complex, and the requirements for programmers have increased, and there are requirements for class loading and concurrency knowledge. And reflection can brute force private constructors.
the code
/** * @author : echo_Huang Shi * @description: Lazy mode will be initialized when called * @date : 2023/2/6 16:45 */ public class LazySingle { private static Object lock=new Object(); private LazySingle() { } //Prohibition of command rearrangement private volatile static LazySingle lazySingle = null; public static LazySingle getSingleInstance() { if (lazySingle == null) { //At this time, multiple threads come in, such as thread A B synchronized (lock) { //At this point lazySingle may have been initialized and needs to be re-judged // If A thread comes in and initializes, B does not need to be initialized after coming in, so it needs to be judged again // Reasons to use the volatile keyword The initialization step is not atomic. // It is divided into three steps. The first step is to allocate memory space // The second step initialization // The third step is to assign the first address of the memory to the variable // For example, the third step and the first step have been completed, but the second step is time-consuming and has not yet been completed. // lazySingle == null This judgment is true. At this time, the object is returned directly, and an incomplete object is returned. // The volatile keyword guarantees that the second step must be completed before the third step is completed, and instructions cannot be rearranged if (lazySingle == null) { lazySingle = new LazySingle(); } } } return lazySingle; } /** * test * @param args */ public static void main(String[] args) { for (int i=0;i<50;i++){ Thread thread=new Thread(){ @Override public void run() { System.out.println("Get a singleton instance: "+getSingleInstance()); } }; thread.start(); } } }
enumeration mode
Joshua Bloch, Google's chief Java architect, author of "Effective Java", and creator of the Java collection framework, mentioned in Effective Java:
The single-element enumeration type has become the best way to implement Singleton.
principle
The Java virtual machine guarantees the uniqueness of enumeration objects, so each enumeration type and defined enumeration variables are unique in the JVM. Guaranteed by the virtual machine.
advantage
It can avoid multi-thread synchronization problems; it can also prevent re-creation of new objects through reflection and deserialization. In many excellent open source codes, we can often see singleton pattern classes implemented using enumeration.
shortcoming
Perhaps the unfamiliarity with enumeration is its shortcoming.
the code
/** * @author : echo_Huang Shi * @description: Enumeration Implementation Singleton * @date : 2023/2/6 17:11 */ public class EnumSingleton { private EnumSingleton(){} static enum SingletonEnum{ //Create an enumeration object as a singleton object INSTANCE; private EnumSingleton enumSingleton; private SingletonEnum(){ enumSingleton=new EnumSingleton(); } public EnumSingleton getInstance(){ return enumSingleton; } } public static EnumSingleton getInstance(){ return SingletonEnum.INSTANCE.getInstance(); } public static void main(String[] args) { for (int i=0;i<50;i++){ Thread thread=new Thread(){ @Override public void run() { System.out.println("Get a singleton instance: "+getInstance()); } }; thread.start(); } } }
test verification
Summarize
Three implementation methods are briefly introduced. Hungry man mode, lazy man mode and enumeration mode. It is recommended to use the enumeration method. If you have any suggestions, welcome to discuss.