Singleton pattern of design pattern and thread safety

Keywords: Java

Preface

The single case model can be divided into "hungry man model" and "lazy man model". Let's talk about singleton mode today, especially in multithreading.

Starving model

class Singleton{
    private static Singleton singleton = new Singleton();

    private Singleton(){}

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

This mode is called the starved Han mode of single case mode. This mode is thread safe.

Slacker mode

class LazySingleton{
    private static LazySingleton lazySingleton;

    private LazySingleton(){}

    public static LazySingleton getInstance(){
        if(lazySingleton == null){
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }
}

This is the lazy mode of singleton mode, which initializes the object only when it is first called. In this case, there will be non thread safety problems in the case of multithreading. So let's solve the thread safety problem of lazy mode.

Synchronization solution

class LazySingleton{
    private static LazySingleton lazySingleton;

    private LazySingleton(){}

    synchronized public static LazySingleton getInstance(){
        if(lazySingleton == null){
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }
}

Using the synchronized keyword to set the get method as the synchronization method can solve the thread safety problem, but the low efficiency is a problem. Let's consider optimizing the efficiency. We can use the synchronization code block, because we only have the line safety problem at the initialization place.

Synchronization code block resolution

class LazySingleton{
    private static LazySingleton lazySingleton;

    private LazySingleton(){}

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

Synchronization code block can also solve the thread safety problem, but the above method is not very different from the efficiency of synchronization method. Our key synchronization code is actually lazySingleton = new LazySingleton(); as long as you add a synchronization identifier to it, there will be a problem that multiple threads determine that they need to initialize this class instance, but only one operation can be performed, and the later is blocked. At this time, once the previous thread is instantiated, the later thread will be instantiated, so we need to move on Line check again to determine whether it has been instantiated. This is DCL (double check) to implement more fine-grained synchronization code block.

DCL solution

class LazySingleton{
    private static LazySingleton lazySingleton;

    private LazySingleton(){}

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

Then I'll finish the introduction of the single example mode. If there are any mistakes in the above questions, please leave a message and let me know. I'll modify it as soon as possible to prevent misleading the readers. Thank you!

Posted by svivian on Sun, 01 Dec 2019 15:45:16 -0800