The source code is in mine github and gitee Get in
introduce
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.
be careful:
- 1. A singleton class can only have one instance.
- 2. A singleton class must create its own unique instance.
- 3. A singleton class must provide this instance to all other objects.
Implementation mode
Hungry Chinese singleton (static constant, thread safety)
As the name suggests, the hungry Chinese singleton is "hungry", so you create a unique singleton instance at the beginning, but if you haven't used this instance, it will cause a waste of memory
/** * Hungry Han style single case * Advantages: simple, the instantiation is completed when the class is loaded, avoiding the problem of thread synchronization and thread safety * Disadvantages: since this class has been instantiated, if this instance is not used from beginning to end, it will cause a waste of memory */ public class SingletonTest01 { public static void main(String[] args) { Signleton instance1= Signleton.getInstance(); Signleton instance2 = Signleton.getInstance(); System.out.println(instance1==instance2); System.out.println(instance1.hashCode()); System.out.println(instance2.hashCode()); } } class Signleton{ //1. The constructor is privatized and cannot be created externally through new private Signleton(){ } //2. Create object instances internally private final static Signleton instance = new Signleton(); //3. Provide a public static method to return the instance object public final static Signleton getInstance(){ return instance; } }
Output results
true 1163157884 1163157884
You can see that the output is the same instance
Hungry Han style singleton (static code block, thread safety)
It is similar to the previous method, except that the class instantiation process is placed in the static code block, that is, when the class is loaded,
Just execute the code in the static code block. The advantages and disadvantages are the same as before
/** * It is similar to the previous method, except that the class instantiation process is placed in the static code block, that is, when the class is loaded, * Just execute the code in the static code block. The advantages and disadvantages are the same as before */ public class SingletonTest02 extends Thread{ public static void main(String[] args) { Signleton instance1= Signleton.getInstance(); Signleton instance2 = Signleton.getInstance(); System.out.println(instance1==instance2); System.out.println(instance1.hashCode()); System.out.println(instance2.hashCode()); } } class Signleton{ //1. The constructor is privatized and cannot be created externally through new private Signleton(){} //2. Create object instances internally private static Signleton instance; static {//Static code blocks are used to create singleton objects instance = new Signleton(); } //3. Provide a public static method to return the instance object public final static Signleton getInstance(){ return instance; } }
output
true 1163157884 1163157884
Lazy (thread unsafe)
Similarly, as the name suggests, the lazy form is very lazy. It creates an instance only when you use it.
/** * Starving - thread unsafe * Advantages: it has the effect of lazy loading, but it can only be used under single thread * If in multithreading, if a thread enters the if judgment statement block, * If another thread enters the judgment statement before it has time to execute downward, multiple instances will be generated (contrary to the singleton mode), * Don't use this method in actual development */ public class SingletonTest03 { public static void main(String[] args) { for (int i = 0; i <10 ; i++) { new Thread(() -> System.out.println(Signleton.getInstance().hashCode()) ).start(); } } } class Signleton{ private static Signleton instance; private Signleton(){} //Provide a static public method. Create instance only when the method is called public static Signleton getInstance(){ if(instance == null){//If it is empty, create the object again instance = new Signleton(); } return instance; } }
output
546405844 135417039 135417039 802181073 135417039 135417039 135417039 802181073 135417039 135417039
Here I choose an extreme case. If your computer is well configured, it may run several times and the results are consistent with the singleton mode.
Lazy (synchronous method, thread safety)
The reason why the above method is thread unsafe is that in the case of multiple threads, multiple threads may judge whether to create a single instance at the same time. To solve this problem, you only need to synchronize the getInstance() method
/** * It solves the problem of thread insecurity * However, the efficiency is greatly reduced. When each thread wants to obtain an instance, it needs to synchronize the execution of getInstance () method */ public class SingletonTest04 { public static void main(String[] args) { for (int i = 0; i <10 ; i++) { new Thread(() -> System.out.println(Signleton.getInstance().hashCode()) ).start(); } } } class Signleton{ private static Signleton instance; private Signleton(){} //Provide a static public method. Create instance only when the method is called public static synchronized Signleton getInstance(){ if(instance == null){//If it is empty, create the object again instance = new Signleton(); } return instance; } }
result
802181073 802181073 802181073 802181073 802181073 802181073 802181073 802181073 802181073 802181073
However, synchronized is a very heavy synchronization lock, and we synchronize every time we execute getInstance(), which greatly affects the efficiency
Lazy (double check, thread safe)
Double check lock, also known as double check lock, combines the advantages and disadvantages of lazy type and hungry type. In the above code implementation, the feature is that a layer of if condition judgment is added inside and outside the synchronized keyword, which not only ensures thread safety, but also improves execution efficiency and saves memory space compared with direct locking
/** * Lazy mode - double check * Two if judgment checks are performed to ensure thread safety * Determine whether it needs to be instantiated again by judging whether it is empty */ public class SingletonTest05 { public static void main(String[] args) { for (int i = 0; i <10 ; i++) { new Thread(() -> System.out.println(Signleton.getInstance().hashCode()) ).start(); } } } class Signleton{ private static volatile Signleton instance;//volatile ensures visibility private Signleton(){} //It provides a static thread check and a solution to the problem of lazy code public static Signleton getInstance() { if (instance == null) { synchronized (Signleton.class) { if (instance == null) { instance = new Signleton(); } } } return instance; } }
Operation results
79372097 79372097 79372097 79372097 79372097 79372097 79372097 79372097 79372097 79372097
Recommended use
Static inner class (thread safe)
/** * Static inner classes implement singleton mode * This method adopts the class loading mechanism to ensure that there is only one thread when initializing the instance * The static inner class will not be instantiated immediately when the Signleton class is loaded, but only when instantiation is required * The static properties of a class are initialized only when the class is first loaded * It avoids thread insecurity and uses static internal classes to realize lazy loading with high efficiency */ public class SingletonTest07 { public static void main(String[] args) { for (int i = 0; i <10 ; i++) { new Thread(() -> System.out.println(Signleton.getInstance().hashCode()) ).start(); } } } class Signleton{ //Constructor private private Signleton(){} //Static inner class, which has a static attribute signeton private static class SignletonInstance{ private static final Signleton instance = new Signleton(); } //Provide a static public method and directly return signletoninstance instance public static Signleton getInstance() { return SignletonInstance.instance; } }
result
79372097 79372097 79372097 79372097 79372097 79372097 79372097 79372097 79372097 79372097
This method is relatively simple and recommended
Enumeration (thread safe)
/** * @author codermy * @createTime 2020/5/14 * Enumeration method to implement singleton mode * With jdk1 5 to implement the singleton mode, * It can not only avoid the problem of multi-threaded synchronization, but also prevent deserialization and re creation of new objects */ public class SingletonTest08 { public static void main(String[] args) { Singleton singleton = Singleton.INSTANCE; singleton.Ok(); for (int i = 0; i <10 ; i++) { new Thread(() -> System.out.println(Singleton.INSTANCE.hashCode()) ).start(); } } } enum Singleton{ INSTANCE;//attribute public void Ok(){ System.out.println("ok"); } }
result
ok 858497792 858497792 858497792 858497792 858497792 858497792 858497792 858497792 858497792 858497792
It can be seen that enumeration implements the singleton mode, which is the most concise and recommended. But it is precisely because of its simplicity that the readability is poor