Java design pattern -- singleton pattern (code explanation, lazy and hungry patterns)

Article catalogue

Design mode - singleton mode

What is singleton mode?

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. Create an instance in the class, and create only one instance

2. If you want to call this object outside the class, you must call getInstance method to get the instance. The advantage is to reduce the overhead of creating and destroying objects

3. Only the unique instance provided by the class can be obtained

Lazy mode

Explain that a lazy man is lazy loading. When a class is loaded, it will not create an instance. It will only be created when it is called for the first time.

public class Singleton {

/**
* The following is the code of lazy mode
*/

    // Thread safety problems will arise. Double check lock is used to ensure safety

    private static Singleton instance = null;
  
   // The class loading process does not create an instance, and the instance is set to null

    public Singleton() {
    }

    public static Singleton getInstance(){
    // An instance is not created until the class is called for the first time
        if(instance==null){
            return instance = new Singleton();
        }
    // The instance created above is used for each subsequent instance call
        return instance;
    }

}

Benefits: instances are created only when resources are called, so resources are saved.

Disadvantages: lazy mode brings thread safety problems

If multiple threads obtain instances at the same time, they are obtained for the first time. Execute the new instance in the if(instance==null) statement, so multiple instances will be created.

How to solve the thread safety problem?

1. Use double check lock

First if(instance==null)

First judge whether the instance exists, and then lock it if it does not exist

Second if(instance==null)

When multiple threads call the object for the first time, only one thread can enter to avoid creating multiple objects

 public static Singleton getInstance(){
        if (instance==null) { // First judge whether the instance exists, and then lock it if it does not exist
            synchronized (Singleton.class) {
                if(instance==null){// In the case of multithreading, only one can enter, avoiding the creation of multiple objects.
                    return instance = new Singleton();
                }
            }
        }
        return instance;
    }

2.volatile modifies the instance object and prohibits instruction reordering

 private volatile static Singleton instance = null;

Instance = new Singleton is actually divided into three steps

1. Allocate memory space for new Singleton

2. Initialize object instance

3. The instance variable points to this memory address

The initialization time is a little slow, so the JVM instructions are rearranged and the order is changed from 1 - > 3 - > 2. In the case of single thread, there is no problem. However, in the case of multithreading, the first thread goes in and executes 1-3. At this time, an instance of the second thread is not null and directly returns the uninitialized instance object, which obviously causes thread safety problems.

So use volatile to prevent instruction rearrangement.

Thread safe lazy mode

public class Singleton {

    /**
 * The following is the code of lazy mode
 */

    // There will be thread safety problems. Double check lock is used to ensure safety, and volatile is used to prohibit instruction reordering

    private volatile static Singleton instance = null;

    public Singleton() {
    }

    public static Singleton getInstance(){
        if (instance==null) {
            synchronized (Singleton.class) {
                if(instance==null){
                    return instance = new Singleton();
                }
            }
        }
        return instance;
    }

}

Hungry man model

Understand the hungry man. Because he is too hungry, he wants to eat as soon as he gets something. Here is the process of class loading, so he can directly create a unique instance.

Benefits: no thread safety issues

Disadvantages: unlike lazy mode calling to create an instance, this is to create an instance when the class is loaded, so if it has not been called, you have to create an instance, which wastes resources.

public class Singleton {
    private static Singleton instance = new Singleton();

    public Singleton() {
    }
    // Call the method to get the instance, only read, so there is no thread safety problem
    public static Singleton getInstance(){
        return instance;
    }
}

Posted by reece_1989 on Sun, 17 Apr 2022 12:13:44 +0930