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")); } }