The singleton pattern is one of the 23 design patterns. It is a relatively simple design pattern. Its purpose is to return the same object no matter how many times it is called. Its characteristic is that the constructor is privatized.
It is divided into two structures, one is the lazy man style and the other is the hungry man style. They each have their own advantages and disadvantages. Let’s start with the hungry man style. The code is as follows:
public class Single { private static Single single = new Single(); private Single() { } public Single getInstance() { return single; } }
It can be seen from the above program that although our purpose of loading the same object has indeed been achieved, the single object will be created when the program is loaded. When this class has multiple such methods, we may not use them. Most singletons in this object will cause a waste of memory. So the lazy singleton pattern emerged. The code is as follows:
public class Single { private static Single single = null; private Single() { } public Single getInstance() { if(single==null){ single = new Single(); } return single; } }
In this way, the object will be new only when we actually call it, but there is a problem with this.
When the second piece of code above is called by two threads when it is loaded for the first time, two different objects will be generated, so it is thread unsafe. At this time, you will think of adding a Lock, the code after locking is as follows:
public class Single { private static Single single = null; private Single() { } public synchronized Single getInstance() { if (single == null) { single = new Single(); } return single; } }
This does achieve thread safety, but when the locking method needs to perform a lot of things, calling this method will take a long time, which is fatal to the server, because if a thread keeps calling this method, There is no way to adjust other threads, and the server will be blocked. Then the upgraded code is as follows:
public class Single { priate static Single single = null; private Single() { } public Single getInstance() { if (single == null) { synchronized (Single.class) { single = new Single(); } } return single; } }
After careful observation, I found that there is no lock in this way. When two threads arrive at the getInstance() method if judgment for the first time, one of them must be blocked. After the other one completes execution, the blocked thread will no longer To determine whether it is empty, an object will still be created. In this way, multiple objects will be generated, and then upgraded. The resulting code is as follows:
public class Single { private static Single single = null; private Single() { } public Single getInstance() { if (single == null) { synchronized (Single.class) { if (single == null) { single = new Single (); } } } return single; } }
In this way, the above problem will not occur, and it will only be locked once, because when the method is executed for the second time, the if judgment will be skipped and the single will be returned directly. It will not be locked again, and the execution efficiency will be very high.
But even so, there is still a problem, because we cannot be sure whether the object is assigned a value in the memory first or the object is created first, so the second program may get a half-initialized object. In jdk1. After 5, we can use the volatile keyword to avoid this situation. The code is as follows:
public class Single { private static volatile Single single = null; private Single() { } public Single getInstance() { if (single == null) { synchronized (Single.class) { if (single == null) { single = new Single(); } } } return single; } }
But this situation is rarely used. I am just here to learn, hehe