Java design pattern (singleton design pattern)

catalogue

1, Hungry mode / load now

2, Lazy mode / lazy loading (thread unsafe)

3, Lazy mode (thread safe)

4, Lazy mode (DCL: double checked locking)

5, Static inner class (optimal method)

Singleton pattern definition: ensure that a class has only one instance and provides a global access point.

There are three typical features of singleton mode: 1. There is only one instance. 2. Self instantiation. 3. Provides a global access point.

1, Hungry mode / load now

public class Singleton {

    // Set the self instantiated object as a property and decorate it with static and final
    private static final Singleton instance = new Singleton();
    
    // Construction method privatization
    private Singleton() {}
    
    // The static method returns the instance
    public static Singleton getInstance() {
        return instance;
    }
}

Advantages: it is simple to implement and has no multi-threaded synchronization problem.

Disadvantages: when class Singleton   When the class is loaded, the static instance will be initialized, and the static variable will be created and allocated memory space. Since then, the static instance object has occupied this memory (even if you haven't used this instance). When the class is unloaded, the static variable will be destroyed and the occupied memory will be released. Therefore, memory will be consumed under certain conditions.

2, Lazy mode / lazy loading (thread unsafe)

public class Singleton {

    // Set the self instantiated object as a property and decorate it with static
    private static Singleton instance;
    
    // Construction method privatization
    private Singleton() {}
    
    // The static method returns the instance
    public static Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

Advantages: it is relatively simple to implement when the class Singleton   When it is loaded, the instance of the static variable static is not created and memory space is allocated. When the getInstance method is called for the first time, the instance variable is initialized and memory is allocated. Therefore, memory will be saved under certain conditions.

Disadvantages: in a multithreaded environment, there is no guarantee that there is only one single instance, and there may be multiple instances.

3, Lazy mode (thread safe)

public class Singleton {

    // Set the self instantiated object as a property and decorate it with static
    private static Singleton instance;
    
    // Construction method privatization
    private Singleton() {}
    
    // The static method returns the instance and adds the synchronized keyword to achieve synchronization
    public static synchronized Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

Advantages: in the case of multithreading, it ensures the thread safety of "lazy mode".

Disadvantages: as we all know, in the case of multithreading, the synchronized method is usually inefficient. Obviously, this is not the best implementation scheme.

4, Lazy mode (DCL: double checked locking)

public class Singleton {

    // Set the self instantiated object as a property and decorate it with static
    private static Singleton instance;
    
    // Construction method privatization
    private Singleton() {}
    
    // The static method returns the instance
    public static Singleton getInstance() {
        // Check whether instance is instantiated for the first time. If it does not enter the if block
        if(instance == null) {
            synchronized (Singleton.class) {
                // A thread obtains a class lock. Before instantiating the object, check whether the instance has been instantiated for the second time. If not, the object is finally instantiated
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

Advantages: the advantage of DCL mode is that it is created only when the object needs to be used. instance== null is judged for the first time. In order to avoid unnecessary locking, the instance is locked and re instantiated when it is loaded for the first time. This can not only save memory space, but also ensure thread safety. However, due to the out of order execution function of jvm, DCL will also have thread insecurity.

INSTANCE = new SingleTon(); In fact, the execution of this step in the jvm is divided into three steps:

1. Open up memory space in heap memory.
2. Instantiate the parameters in SingleTon in heap memory.
3. Point the object to the heap memory space.

Because the jvm has the function of out of order execution, it may execute 3 before 2 is executed. If it is switched to thread B at this time, because 3 is executed, the INSTANCE is not empty and will be directly used. In this case, an exception will occur. This is the famous DCL failure problem.

However, after JDK1.5, the official also found this problem, so it concretized volatile, that is, in JDK1.6 and later, as long as it is defined as private volatile static SingleTon   INSTANCE = null; DCL failure can be solved. Volatile ensures that instance is read in main memory every time, which will sacrifice a little efficiency, but it is harmless.

5, Static inner class (optimal method)

public class SingleTon{
  private SingleTon(){}
 
  private static class SingleTonHoler{
     private static SingleTon INSTANCE = new SingleTon();
 }
 
  public static SingleTon getInstance(){
    return SingleTonHoler.INSTANCE;
  }
}

The advantage of static internal classes is that when an external class is loaded, the internal class does not need to be loaded immediately. If the internal class is not loaded, the INSTANCE will not be initialized, so it does not occupy memory. That is, when SingleTon is loaded for the first time, it is not necessary to load singletonholder. Only when getInstance() method is called for the first time, will INSTANCE be initialized. Calling getInstance() method for the first time will cause the virtual machine to load singletonholder class. This method can not only ensure thread safety, but also ensure the uniqueness of SingleTon, but also delay the instantiation of SingleTon.

---------------------------------------------------------------------------------------------------------------------------------

reference resources:

cjava design pattern -- single case pattern - Yinxiao and xuxing - blog Park

Single example of design pattern - chenghaow - blog Garden

Tags: Algorithm

Posted on Fri, 24 Sep 2021 05:54:52 -0400 by ivytony