Initial understanding of singleton mode

Singleton mode

Singleton mode is a design mode,
   the so-called design patterns, like chess scores, have produced corresponding solutions for some specific scenarios.

For example:
  the DataSource we created when learning JDBC should be a singleton.
  in addition, there are some classes responsible for loading data into memory in actual development, which should also be singletons,
   because such a class generally has several G, or even more than a dozen g. if it is not a single instance, it will occupy a lot of memory each time,

The singleton pattern is equivalent to the mandatory provision that a class can only have one instance from the perspective of syntax.

Implementation of singleton mode

   the implementation of singleton mode mainly relies on static keyword ~ (members modified by static keyword are called static members),
  in Java, after a member is modified by static, it becomes a "class attribute" rather than an "instance attribute". We can only call it through: class name Instead of creating an instance object of a class, it is called as a static member.

Style of singleton mode

Hungry man model

Hungry man, once hungry, I want to eat three bowls

/**
 * @Name: ThreadDemo1
 * @Description:     Hungry man model
 * @Author: panlai
 * @Date: 2021/8/10 10:00
 */

public class ThreadDemo1 {
    //The Singleton class is a Singleton class with only one instance
    static class Singleton{
        //Create a member and save a unique Singleton instance
        private static Singleton instance = new Singleton();
        //Get the instance through the public method
        public static Singleton getInstance(){
            return instance;
        }
        //Then set the construction method of the class to private to avoid other members building instances of the class
        private Singleton(){};
    }


    public static void main(String[] args) {
        Singleton s = Singleton.getInstance();
    }
    
}

Lazy mode

Lazy, lazy to move, eat a few bowls and wash a few bowls.

/**
 * @Name: ThreadDemo2
 * @Description:        Lazy mode
 * @Author: panlai
 * @Date: 2021/8/10 10:07
 */

public class ThreadDemo2 {
    //Realization of lazy mode
    //The time to create an instance is the first time to use the getInstance method, which is later than the hungry man mode
    static class Singleton {
        private static Singleton instance = null;
        public static Singleton getInstance(){
            //It is created only when the instance is used. It is not created at the beginning.
            if (instance == null){
                instance = new Singleton();
            }
            return instance;
        }
        private Singleton(){}
    }

    public static void main(String[] args) {
        Singleton s = Singleton.getInstance();
    }
    
}

It is generally believed that the lazy mode is better (but it is not absolute. It mainly depends on the use scenario, but the lazy mode is more efficient).
Because:

Hungry man mode: (wash the dishes immediately) after eating three bowls of rice, wash three bowls,
Lazy mode: after eating three bowls of rice, don't wash them. Wash a few bowls when you want to eat next time. (cost savings)

The Linux command less uses the lazy mode,
Each time you open a file, only the screen data used in front of you is loaded into memory, so the opening speed is relatively fast. It is reloaded when turning pages,
However, if you use Notepad to open it, all the data will be loaded out and then can be seen. The efficiency is relatively low.

Thread safety issues in singleton mode

Which of the above two is thread safe? Which is thread unsafe?
The answer is: lazy mode has thread safety problems.
The code execution process of lazy mode in the above code is roughly divided into the following four steps:

But if two threads execute in this way,
We will find that after thread 1 creates a new instance, thread 2 creates another instance before saving. In the whole process, two instances are created, which is not in line with the idea of singleton mode. ()

So how to ensure thread safety?

Locked synchronized
reference resources: How to ensure thread safety?
If synchronized is added outside the getInstance method, it means that all internal operations are serial,
If it is added to the method, it is only judged that the new operation is serial, which improves the efficiency (serial is not as efficient as parallel).

/**
 * @Name: ThreadDemo3
 * @Description:        Lock to solve lazy thread insecurity
 * @Author: panlai
 * @Date: 2021/8/10 10:33
 */

public class ThreadDemo3 {
    //Realization of lazy mode
    //The time to create an instance is the first time to use the getInstance method, which is later than the hungry man mode
    static class Singleton {
        private static Singleton instance = null;
        //You can add the synchronized keyword to the getinstance method, but it's not good and rude
        public static Singleton getInstance(){
            //If the keyword is written internally, the serial code is reduced and the efficiency is improved
            synchronized(Singleton.class){
                if (instance == null){
                    instance = new Singleton();
                }
            }
            return instance;
        }
        private Singleton(){}
    }
}

   however, this cannot escape an invariable Law:
     locking is destined to have nothing to do with efficiency.
   however, the above method can be optimized, because only instances are not initialized and locking operation is required when creating instances. Therefore, if the above method is followed, unnecessary locking and unlocking operation will be caused, wasting time and resources.
    therefore, you only need to make an if condition judgment before locking. If the instance has been initialized, you don't need to make the second locking judgment operation.
As follows:

        public static Singleton getInstance(){
            //If the keyword is written internally, the serial code is reduced and the efficiency is improved
            if (instance == null){
                synchronized(Singleton.class){
                    if (instance == null){
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }

The first if judgment is to judge whether the thread is initialized. If it has been initialized, there is no need to lock it. If it is not initialized, lock it and initialize it., It improves efficiency and saves time.

In addition, when calling this method by multiple threads, you also need to use the volatile keyword to correct that the values read by the thread are the latest values in memory.

Keywords: Multithreading

Added by sunnyk on Sat, 25 Dec 2021 23:54:53 +0200