Article benefits: Alibaba coding specification - download of each version
In programming, we often only need a global instance. For example, the task manager, database connection pool, thread pool, etc. in Windows use the singleton mode.
There are many ways to implement Singleton.
To implement a singleton, consider the following:
1. Who creates the object instance: you can't give it to others, so you can only create the object yourself, so the construction method needs to be set to private
2. Can only one instance be guaranteed in a multithreaded environment
Let's learn several common implementation methods
Hungry Chinese implementation:
public class SingletonTest { // An instance is created whenever the class is loaded into the JVM private static SingletonTest instance = new SingletonTest(); // Private constructs ensure that instances cannot be created by others private SingletonTest(){} // Provide an interface to the outside world to obtain a unique instance public static SingletonTest getInstance(){ return instance; } }
Test: get two instances respectively and compare whether their memory addresses are equal
public static void main(String[] args) { SingletonTest instance1 = SingletonTest.getInstance(); SingletonTest instance2 = SingletonTest.getInstance(); System.out.println(instance1 == instance2); // true }
The result is true and the thread is safe
Lazy implementation
public class SingletonTest02 { // Declare an instance private static SingletonTest02 instance; // Private constructs ensure that instances cannot be created by others private SingletonTest02(){} // Provide an interface to the outside world to obtain a unique instance public static SingletonTest02 getInstance(){ if (instance == null){ try { Thread.sleep(1); } catch (InterruptedException e) { } // Create an instance when called instance = new SingletonTest02(); } return instance; } public static void main(String[] args) { for (int i=0; i<100; i++){ new Thread(() -> { System.out.println(SingletonTest02.getInstance().hashCode()); }).start(); } } }
Test: start 100 threads to get the instance at the same time and print its hashcode. give the result as follows
1406241281 1406241281 1406241281 1406241281 898323977 139505508 139505508 103512977
hashcode is different, which means that this writing method produces multiple instances in a multithreaded environment, which is contrary to the topic
Improved lazy style
Improvement scheme: synchronous lock + double judgment
// Provide an interface to the outside world to obtain a unique instance public static SingletonTest03 getInstance(){ // First judgment if (instance == null){ try { Thread.sleep(1); } catch (InterruptedException e) { } // Create an instance when called synchronized(SingletonTest03.class){ // Second judgment if (instance == null){ instance = new SingletonTest03(); } return instance; } } return instance; }
explain:
The first one is empty. Some people think it can be removed. After removal, there is no thread safety problem in terms of thread safety, but it is not the best in terms of execution efficiency. If it is removed, how many threads must hold how many locks, which is inefficient.
Another lazy implementation - static inner class implementation
public class SingletonTest04 { // Private constructs ensure that instances cannot be created by others private SingletonTest04(){} // Private inner class private static class Inner{ // Declare an instance in the inner class private static final SingletonTest04 instance = new SingletonTest04(); } // Provide an interface to the outside world to obtain a unique instance public static SingletonTest04 getInstance(){ return Inner.instance; } public static void main(String[] args) { for (int i=0; i<100; i++){ new Thread(() -> { System.out.println(SingletonTest04.getInstance().hashCode()); }).start(); } } }
Note: the above writing method is still lazy loading. Who ensures that there is only one instance under multithreading? It is the JVM itself. The JVM loads the internal class only when it obtains the instance, and it only loads it once. Ensuring an instance is the same as hungry Chinese style.
With so many single mode implementations, one of the authors of developing the Java language can't see it anymore. He can solve the problem directly
Enumeration implementation
public enum SingletonTest05 { instance; public static void main(String[] args) { for (int i=0; i<100; i++){ new Thread(() -> { System.out.println(SingletonTest05.instance.hashCode()); }).start(); } } }
Advantages of using enumeration to implement singleton:
1. Ensure thread safety
2. Prevent deserialization from creating objects
The above are the common implementation methods of single instance, each with its advantages and disadvantages. However, in the actual design of single instance, the problems considered are not only thread safety, such as whether the common distributed cluster (multi JVM process) is an object instance, whether the instance is a single instance, and whether the instance is maliciously created after reverse sequencing.
--- END ---
Pay attention to the official account of Java Island, making millions of points every day, and grow up together with Xiaobian Java!