“This is the third day of my participation in the First Challenge 2022. For details: First Challenge 2022”

preface

As a developer, this singleton is no longer familiar, but as a variety of singleton implementation patterns, I personally feel that double checklock is very rare implementation, let’s briefly analyze its principle.

The body of the

Let’s start with the Java version, and then we’ll get into the Kotlin code and we’ll compare.

Code implementation

Java code implementation is as follows:

// Double check lock singleton
public class SingleInstance {
    // Must be volatile modifier see analysis 1
    private volatile static SingleInstance instance;
    // Privatize constructor
    private SingleInstance() {
    }

    public static SingleInstance getInstance() {
        // See analysis 2 for the first call
        if (instance == null) {
            synchronized (SingleInstance.class) {
                // The second call sees analysis 3
                if (instance == null) {
                    // Create an instance
                    instance = newSingleInstance(); }}}returninstance; }}Copy the code

First of all, the synchronized keyword does not modify the entire getInstance function, because it can be used in a lot of places and cause other threads to block, which is not good, so only one piece of code is synchronized.

Analysis of 2: Why to when it enters the synchronized block to empty, if have thread and thread B, then thread A judgment first instance is null, it entered the synchronized code block, to create the object, and then thread B came in, it don’t have to enter the synchronization code is fast, can return directly, actually also is lazy loading, Can speed up the execution.

Analysis of 3: Why in the synchronized code block to make A judgment, if have thread and thread B, it is both A method is called first, followed by B calls, then A and B to the analysis of the 2 out empty is empty, so A enters the synchronized block, B to wait, when entering A synchronized block of code creates objects, A thread to release the lock, and then enter again, B If 3 is not nulled, B will create an instance, which is obviously not in line with the rule.

Analysis 1: Why volatile?

Because the code for creating a new instance:

instance = new SingleInstance();

Instead of an atomic operation, this simple assignment can be divided into 3 steps:

Allocate memory to SingleInstance

2. Call the SingleInstance constructor

Set instance to the allocated memory space

These are three logical steps, and the instance is not null only if you press 1, 2, and 3.

But the Java memory model allows this instruction to be reordered, so these 3 steps could be 123 or 132, so there’s a problem here.

If thread A and thread B, thread A has run to analyze the code at 3, then this instruction is 132, just finished executing step 3, when thread B runs to analyze the code at 1, it will find that instance is not null, then thread B will directly return, resulting in an error.

If we know that the reason that the volatile keyword is the solution to this, it can prohibit instruction reordering, and ensure that all threads see this variable is consistent, also is not read from the cache (behind this feature have a chance to say), so in creating the instance instance, its steps are 123, won’t make a mistake.

conclusion

In fact, a small double check lock singleton are still quite a lot of knowledge, we will analyze Kotlin singleton are generally how to implement and principle.