[Interview question: handwritten singleton mode]

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.

Tags: Java Design Pattern Multithreading Singleton pattern

Posted by synical21 on Wed, 08 Feb 2023 18:51:03 +0530