Design pattern - singleton pattern of Creator pattern

1. Singleton mode

Introduction

Implementation of singleton mode

Hungry Chinese style: class loading will cause the single instance object to be created. When a class is loaded, whether it is used or not, the object will be in memory, which will cause a waste of memory.

Mode 1: static variable mode

package Creator mode.Singleton mode;

//Singleton static member variable
public class Singleton {
    //1. Private construction method. The singleton mode allows an object. If the outside world cannot access it, the object cannot be created
    private Singleton(){}
    //2. Create this class object in this class and return the object in the static method, so this property needs to be static
    private static Singleton instance = new Singleton();
    //3. Provide a public way to access the object so that the outside world can obtain the object
    //The outside world cannot create this object, and ordinary methods cannot be called without an object, so the class name should be used Static method name to call the method, so as to obtain the object
    public static Singleton getInstance(){return instance;};
}
package Creator mode.Singleton mode;

public class Client {
    public static void main(String[] args) {
        //Create an object of the Singleton class
        Singleton instance = Singleton.getInstance();

        Singleton instance1 = Singleton.getInstance();

        //Judge whether the two objects obtained are the same
        System.out.println(instance == instance1);//Output true
    }
}

Mode 2: static code block mode

package Creator mode.Singleton mode: hungry Chinese static code block mode;

public class Singleton {
    //1. Construction method
    private Singleton(){};
    //2.Singleton object
    private static Singleton instance;
    //3. Assign a value to this object
    static {
        instance = new Singleton();
    }

    public static Singleton getInstace(){
        return instance;
    }
}
package Creator mode.Singleton mode: hungry Chinese static code block mode;

public class Client {
    public static void main(String[] args) {

        Singleton instance = Singleton.getInstace();

        Singleton instance1 = Singleton.getInstace();
        //Judge whether to achieve single example
        System.out.println(instance1 == instance);//true
    }
}

Method 3: enumeration method

Enumeration types are thread safe and can only be loaded once

public enum Singleton {
    INSTANCE;
}
public class Client {
    public static void main(String[] args) {
        Singleton instance = Singleton.INSTANCE;
        Singleton instance1 = Singleton.INSTANCE;
        System.out.println(instance1 == instance);//true
    }
}

Lazy: class loading does not cause the single instance object to be created, but is created when the object is first used.

Mode 1: thread unsafe

package Creator mode.Singleton mode lazy thread unsafe mode;


public class Singleton {
    private Singleton(){};


    //Here, only a variable of type is declared without assignment
    private static Singleton instance;

    public static Singleton getInstance(){
        /*
        In this way, threads are not safe. If there are two threads, when thread 1 executes the judgment statement, the next sentence has not been executed at this time. If thread 2 takes resources,
        Thread 2 is also determined to be null. At this time, when the two threads execute further, they will get objects, which are different.
        */
        if(instance == null){
            instance = new Singleton();
        }
            return instance;
    }
}

Mode 2: thread safety

package Creator mode.Singleton mode lazy thread unsafe mode;


public class Singleton {
    private Singleton(){};


    //Here, only a variable of type is declared without assignment
    private static Singleton instance;
    //The difference from mode 1 is that the keyword synchronized is added
    public static synchronized Singleton getInstance(){
        
        if(instance == null){
            instance = new Singleton();
        }
            return instance;
    }
}

Mode 3: double check lock

For method 2, since the judgment will be false every time after obtaining the object once, you don't need to execute the statement in if every time. No matter which thread is safe when executing return, the thread will be unsafe only when the object is not determined, but every time each thread enters the lock, it will affect the code efficiency, so you need to adjust the lock timing. So there's a double check.

I don't understand the usage of synchronized synchronized parameter and its meaning_ CSDN blog_ synchronized parameter

package Creator mode.Single case mode dual check lock;

public class Singleton {
    private Singleton(){};

    private static Singleton instance;

    public static Singleton getInstance(){
        //In the first judgment, if the instance value is not null, there is no need to preempt the lock and return the object directly.
        if(instance == null){
            //The object of the lock is the bytecode object of the current class
            synchronized (Singleton.class){
                //Second judgment
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;

    }
}

When declaring instance, add volatile after static

Method 4: static internal class method

In the static internal class singleton mode, the instance is created by the internal class. Because the JVM will not load the static internal class during the process of loading the external class, it will be loaded only when the properties / methods of the internal class are called. And initialize its static properties. Because static attributes are modified by static, they are guaranteed to be instantiated only once, and the instantiation order is strictly guaranteed. The attribute of the static inner class is because the attribute can be called without creating an object.

The INSTANCE will not be initialized when the Singleton class is loaded for the first time. Only when getInstance is called for the first time, the virtual machine loads the SingleHolder and initializes the INSTANCE, which can not only ensure thread safety, but also ensure the uniqueness of the Singleton class.  

In the class, it is guaranteed that the object will not be created to occupy memory when the method is not called, because the internal class will be loaded when the method is called.

public class Singleton {
    private Singleton(){

    }
    //Declare static inner classes
    private static class SingletonHolder{
        //Declare and initialize the object. final is to prevent external modification
        private final static Singleton INSTANCE = new Singleton();
    }
    //Provide public access
    public static Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
}

Summary: double check lock and static inner class are recommended for singleton mode. Without considering the waste of space, you can also choose the hungry Chinese enumeration method.

Existing problems

If you want to break the above singleton mode (except enumeration), you can create multiple objects in two ways: serialization and reflection.

Problem solving

Because you haven't learned serialization and reflection yet, leave it empty first

Application of singleton mode in JDK source code

Runtime class

Keywords: Singleton pattern

Added by FraggleRock on Mon, 07 Feb 2022 08:18:55 +0200