Design mode-04 (single case mode)

                                                              Singleton mode

                                                                                                  Personal blog: www.xiaobeigua.icu 

          First, let's learn about the creation mode. The main focus of the creation mode is "how to create objects?", and its main feature is "separating the creation and use of objects".

         This can reduce the coupling degree of the system, and users do not need to pay attention to the creation details of objects.

The creation mode is divided into:

         Singleton mode

         Factory method model

         Abstract engineering pattern

         Prototype mode

         Builder pattern

1.1 introduction to singleton mode

         Singleton Pattern is one of the simplest design patterns in Java. This type of design pattern is a creation pattern, which provides the best way to create objects.

         This pattern involves a single class that is responsible for creating its own objects while ensuring that only a single object is created. This class provides a way to access its unique object, which can be accessed directly without instantiating the object of this class.

                

 

one point two   Structure of singleton mode

The main roles of singleton mode are as follows:

  • Singleton class. Only one instance of a class can be created
  • Access class. Using singleton classes

one point three   Implementation of singleton mode

There are two types of singleton design patterns:

         Hungry Chinese style: class loading will cause the single instance object to be created

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

1. Hungry Han style - mode 1 (static variable mode)

public class Singleton {

    //Construction method privatization
    private Singleton(){};
    
    //Create global immutable singleton object
    private static final Singleton instance=new Singleton();
    
    //Defines the unique static method to get the global singleton object
    public static Singleton getInstance(){
        return instance;
    }
    

}

explain:

         This method declares a static variable of Singleton type at the member position and creates an instance object of Singleton class. The instance object is created as the class loads. If the object is large enough and has not been used, it will cause a waste of memory.

2. Hungry Chinese - mode 2 (static code block mode)

public class Singleton {

    //Construction method privatization
    private Singleton(){};

    //Define global singleton object variables
    private static  Singleton instance=null;

    //Objects created in static code blocks are created when the class is loaded
    static {
        instance=new Singleton();
    }

    //Defines the unique static method to get the global singleton object
    public static Singleton getInstance(){
        return instance;
    }


}

explain:

         In this way, a static variable of Singleton type is declared at the member position, and the object is created in the static code block and for the loading of the class. Therefore, it is basically the same as hungry man mode 1. Of course, this mode also has the problem of memory waste.

3. Lazy - mode 1 (thread unsafe)

public class Singleton {

    //Construction method privatization
    private Singleton(){};

    //Define global singleton object variables
    private static  Singleton instance=null;

    
    //Define the unique static method to obtain the global singleton object, and identify and create the object in the method
    public static Singleton getInstance(){
        if (instance==null){
            instance=new Singleton();
        }  
        return instance;
    }


explain:

         From the above code, we can see that this method declares a static variable of Singleton type at the member position, and does not assign an object. When did the assignment take place? The Singleton class object is created only when the getInstance() method is called to obtain the Singleton class object, which realizes the effect of lazy loading.

         However, if it is a multithreaded environment, thread safety problems will occur due to the competition of multiple threads.

4. Lazy - mode 2 (thread safe)

public class Singleton {

    //Construction method privatization
    private Singleton(){};

    //Define global singleton object variables
    private static  Singleton instance=null;

    //Define the unique static method to obtain the global singleton object, and identify and create the object in the method
    //Add the synchronized keyword to lock this method to ensure data security
    public static synchronized Singleton getInstance(){
        if (instance==null){
            instance=new Singleton();
        }
        return instance;
    }
    
}

explain:

         This method also realizes the effect of lazy loading and solves the problem of thread safety. However, the synchronized keyword is added to the getInstance() method, resulting in a particularly low execution effect of the method (because the whole method is locked, and the granularity of the lock is relatively coarse). From the above code, we can see that the thread safety problem only occurs when initializing instance. Once the initialization is completed, it does not exist.

5. Lazy - mode 3 (double check lock)

         Let's talk about locking in lazy mode. For getInstance() method, most operations are read operations. Read operations are thread safe, so we don't have to make each thread hold a lock to call this method. We need to adjust the timing of locking. Therefore, a new implementation mode: double check lock mode is also produced

public class Singleton {

    //Construction method privatization
    private Singleton(){};

    //Define global singleton object variables
    private static  Singleton instance=null;

    //Define the unique static method to obtain the global singleton object, and identify and create the object in the method
    //In addition, synchronized locks this method to ensure data security
    public static  Singleton getInstance(){
        
        //First determine whether the object is null
        if (instance==null){
            //Use code blocks to reduce the granularity of locks
            synchronized (Singleton.class){
                //Judge again
                if (instance==null){
                    //create object
                    instance=new Singleton();
                }
            }
           
        }
        
        return instance;
    }

}

         The double check lock mode is a very good singleton implementation mode, which solves the problems of singleton, performance and thread safety. The above double check lock mode looks perfect, but it is actually a problem. In the case of multithreading, null pointer problems may occur. The reason for the problem is that the JVM will optimize and reorder instructions when instantiating objects.

         To solve the problem of null pointer exception caused by double check lock mode, you only need to use volatile keyword, which can ensure visibility and order. (those who don't know the volatile keyword can go to my multithreading blog)

public class Singleton {

    //Construction method privatization
    private Singleton(){};

    //Define the global singleton object variable and decorate it with the volatile keyword
    private static volatile   Singleton instance=null;

    //Define the unique static method to obtain the global singleton object, and identify and create the object in the method
    //In addition, synchronized locks this method to ensure data security
    public static  Singleton getInstance(){

        //First determine whether the object is null
        if (instance==null){
            //Use code blocks to reduce the granularity of locks
            synchronized (Singleton.class){
                //Judge again
                if (instance==null){
                    //create object
                    instance=new Singleton();
                }
            }

        }

        return instance;
    }

}

explain:

         The double check lock mode after adding volatile keyword is a better singleton implementation mode, which can ensure thread safety and no performance problems in the case of multithreading.

6. Lazy - mode 4 (static internal class mode)  

         In the static internal class singleton mode, instances are created by internal classes. Because the JVM will not load static internal classes during the process of loading external classes, only the properties / methods of internal classes will be loaded and their static properties will be initialized. Because static attributes are modified by static, they are guaranteed to be instantiated only once, and the instantiation order is strictly guaranteed.

public class Singleton {

    //Private construction method
    private Singleton() {}

    private static class SingletonHolder {
        
        private static final Singleton INSTANCE = new Singleton();
    }

    //Provide a static method to get the object
    public static Singleton getInstance() {
        
        return SingletonHolder.INSTANCE;
    }
}

explain:

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

         Static inner class singleton mode is an excellent singleton mode, which is commonly used in open source projects. Without any lock, it ensures the safety of multithreading without any performance impact and waste of space.

one point three   JDK source code parsing - Runtime class

         The Runtime class represents the Runtime environment of Java programs. Each Java program has a Runtime instance. This class will be created automatically. We can use Runtime.getRuntime()   Method to get the Runtime instance of the current program

The Runtime class is the singleton design pattern used.

Source code:

public class Runtime {

    private static Runtime currentRuntime = new Runtime();
    /**
    * Returns the runtime object associated with the current Java
    application.
    * Most of the methods of class <code>Runtime</code> are instance
    * methods and must be invoked with respect to the current runtime
    object.
    *
    * @return the <code>Runtime</code> object associated with the
    current
    * Java application.
    */

    public static Runtime getRuntime() {
        return currentRuntime;
    }

    /** Don't let anyone else instantiate this class */
    private Runtime() {}
        ...
}

         From the above source code, we can see that the Runtime class uses starving Han style (static attribute) to implement the singleton pattern.

Using methods in the Runtime class

public class RuntimeDemo {

    public static void main(String[] args) throws IOException {
        
        //Get Runtime class object
        Runtime runtime = Runtime.getRuntime();

        //Returns the total amount of memory in the Java virtual machine.
        System.out.println(runtime.totalMemory());

        //Returns the maximum amount of memory that the Java virtual machine attempts to use.
        System.out.println(runtime.maxMemory());

        //Create a new process, execute the specified string command, and return the process object
        Process process = runtime.exec("ipconfig");

        //Get the result after the command is executed, and get it through the input stream
        InputStream inputStream = process.getInputStream();

        byte[] arr = new byte[1024 * 1024* 100];
        int b = inputStream.read(arr);
        System.out.println(new String(arr,0,b,"gbk"));
    }
}

Tags: Java Design Pattern Singleton pattern Runtime

Posted on Sat, 02 Oct 2021 13:49:52 -0400 by peppino