The purpose of the Singleton pattern is to ensure that a class has only one instance and also provides a global access point for it. To prevent other workers from instantiating our class,
You can create a unique constructor for this class and set the visible of the constructor to private. It is worth noting that if we create other non-private constructors, or we do not make any mention of the class at all
For constructors, then other people can still instantiate our class. If we do not want to create a singleton object in advance, we can wait until the first time we use the singleton object, that is,
Lag initialization. There are two reasons for lagging initialization of singleton objects:
1. Maybe at the static initialization time, you don't have enough information on how to initialize a singleton object.
2. The purpose of selecting a lag initialization singleton may be to wait for resources such as database connections, especially in applications where this singleton is not required in certain specific sessions.
If a singleton is initialized in a multithreaded environment, we must be careful to prevent multiple threads from initializing the same time.
Usually, singleton pattern is built in Java language:
Lazy way: refers to the global singleton instance being built when it is used for the first time. Delay initialization.
Hungry Man Method: refers to the global single instance being built during class loading. Urgent initialization.
1. Hungry Chinese singleton
public class Singleton1 { private Singleton1() { } // Define your own instance internally. // Note that this is private. Private static Singleton1 instance = new Singleton1(); /** *//** * Here is a static method for external access to this class, which can be directly accessed * @return */ public static Singleton1 getInstance() { return instance; }}2. Lazy singleton class
public class Singleton2 { private static Singleton2 instance = null; /** *//** * This method is improved compared to the above. It does not require generating objects every time, but the first time * generates instances when used, which improves efficiency! * @return */ public static Singleton2 getInstance() { if (instance == null) instance = new Singleton2(); return instance; }}The following are the main multi-threading problems. In lazy singletons, there is no problem with single threading, but when multi-threading, there may be two or more Singletion2 instances.
For example: when thread 1 judges that instance==null is true, when scanning the new operation, before performing the new operation and after performing the new operation, thread 2 just performs the judgment operation, and the instance is still null. Therefore, thread 2 will also perform the new operation. And so on, under high concurrency, there may be two or more instances of Singletion2. Obviously, this is incorrect.
Therefore, change the code as follows:
public class Singleton3 { private static Singleton3 instance = null; /** *//** * This method is improved compared to the above. It does not require the object to be generated every time, but the first time * generates instances when used, which improves efficiency! * In order to avoid errors in multi-threading, the synchronization flag was added* @return */ public static synchronized Singleton3 getInstance() { if (instance == null) instance = new Singleton3(); return instance; }}But this creates another problem. The methods are synchronized every time the instance is retrieved. Obviously, the performance is very affected, so continue to change the code as follows:
volatile, replace synchronization with a lower cost
Why is volatile cheaper than synchronization?
The cost of synchronization is mainly determined by its coverage range. If the coverage range of synchronization can be reduced, the program performance can be greatly improved.
The coverage of volatile is only at the variable level. Therefore, its synchronization cost is very low.
What is the principle of volatile?
The semantics of volatile are actually to tell the processor not to put me in working memory, please operate me directly in main memory. (See the java memory model for working memory for details)
Therefore, when multi-core or multi-threading accesses the variable, they will directly operate the main memory, which essentially achieves variable sharing.
What are the advantages of volatile?
1. Larger program throughput
2. Less code to implement multi-threading
3. The program has better scalability
4. It is easier to understand, and there is no need for too high learning costs.
What are the disadvantages of volatile?
1. Prone to problems
2. It is difficult to design
volatile uses jdk requires version 1.5 and above.
The improved code is as follows (also called double lock):
public class Singleton4 { private static volatile Singleton4 instance; /** *//** * Double locking to achieve multi-threading application and performance optimization* @return */ public static Singleton4 getInstance() { if (instance == null) { synchronized(Singleton4.class) { //1 if (instance == null) //2 instance = new Singleton4(); //3 } } return instance; }}