Detailed explanation of design mode - single example mode.

Detailed explanation of design mode - single case mode

This article introduces a design pattern - singleton pattern.
 

1, Singleton mode

1. Definitions
As the object creation mode, the singleton mode ensures that a class has only one instance, and instantiates itself and provides this instance to the whole system. This class is called a singleton class.

2. Features
A singleton class can only have one instance.
A singleton class must create its own unique instance.
A singleton class must provide this instance to all other objects.

2, How to create singleton mode

① Lazy, thread unsafe

Lazy style is actually a more vivid appellation. Since you are lazy, you don't have to worry when creating object instances. It will not be created until the object instance is about to be used. Lazy people will not really perform work until they can't get rid of it. Therefore, object instances are not created when loading objects.

public class Singleton {
    private static Singleton instance;
    private Singleton (){}

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

This code is simple and clear, and uses lazy loading mode, but it has fatal problems. When multiple threads call getInstance() in parallel, multiple instances will be created. That is, it doesn't work properly under multithreading.

② Lazy, thread safe

To solve the above problem, the simplest way is to set the entire getInstance() method to synchronized.

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

Although it achieves thread safety and solves the problem of multiple instances, it is not efficient. Because only one thread can call the getInstance() method at any time. However, the synchronization operation is only required when it is called for the first time, that is, when the singleton instance object is created for the first time. This leads to a double check lock.

③ Double check lock

double checked locking pattern is a method of locking using synchronous blocks. Programmers call it a double check lock, because instance == null will be checked twice, once outside the synchronization block and once inside the synchronization block. Why do I have to check again in the synchronization block? Because multiple threads may enter the if outside the synchronization block together, multiple instances will be generated if no secondary verification is performed in the synchronization block.

public static Singleton getSingleton() {
    if (instance == null) {                         //Single Checked
        synchronized (Singleton.class) {
            if (instance == null) {                 //Double Checked
                instance = new Singleton();
            }
        }
    }
    return instance ;
}

④ Starving static final field

Hungry Han style is actually a more vivid appellation. Since you are hungry, you are in a hurry when creating object instances. When you are hungry, you create object instances when loading classes.

This method is very simple. Because the instance of a singleton is declared as static and final variables, it will be initialized when the class is loaded into memory for the first time, so creating the instance itself is thread safe.

public class Singleton{
    //Class is initialized when it is loaded
    private static final Singleton instance = new Singleton();
    
    private Singleton(){}

    public static Singleton getInstance(){
        return instance;
    }
}

The disadvantage is that it is not a lazy initialization mode. The singleton will be initialized at the beginning after loading the class, even if the client does not call the getInstance() method.

The hungry Chinese creation method cannot be used in some scenarios: for example, the creation of a Singleton instance depends on parameters or configuration files. Before getInstance(), a method must be called to set parameters to it, so this Singleton writing method cannot be used.

⑤ static nested class

This method is also recommended in Effective Java.

public class Singleton {  
    private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE; 
    }  
}

⑥ Enum enum

It's too simple to write a single example with enumeration! This is also its biggest advantage. The following code is the usual way to declare enumerated instances.

public enum EasySingleton{
    INSTANCE;
}

We can use easysingleton Instance to access the instance, which is much simpler than calling the getInstance() method. Creating enumerations is thread safe by default, so there is no need to worry about double checked locking, and it can prevent deserialization from causing new objects to be re created.

3, Summary

Generally speaking, there are five ways to write singleton mode: lazy, hungry, double check lock, static internal class and enumeration. The above is the implementation of thread safety. The first method above is thread unsafe and is excluded.

In general, it's better to directly use hungry Chinese style. If lazy initialization is explicitly required, static internal classes are preferred. If deserialization is involved, you will try to use enumeration to implement singleton when creating objects.

Keywords: Java Design Pattern Singleton pattern

Added by TimC on Fri, 21 Jan 2022 12:38:48 +0200