Singleton mode allows a class to have only one instance of an object, reducing the time and space overhead of creating objects frequently. A typical singleton pattern code in single-threaded mode is as follows:
①
1 classsingleton{2 private staticSingleton Singleton; 3 PrivateSingleton () {}4 5 Public StaticSingleton getinstance () {6 if(Singleton = =NULL){7Singleton =NewSingleton (); 18 }9 returnSingleton;Ten } One}
The constructor private makes it impossible for the outside world to instantiate the Singleton class through the constructor, and to obtain an instance only through the getinstance () method. This is a deferred-loading version that instantiates operations when an object is needed. This method can run normally under single thread, but in multi-threaded environment, multiple singleton objects can be produced because there is no synchronization action. The reason is that it is possible to have two threads A and b simultaneously execute to the IF condition judgment statement, a to determine singleton is empty ready to execute//1 when the CPU time slice, B also Judge Singleton is empty, then execute//1, at this time an instance object is created A gets the CPU time slice and then executes the//1, and also creates the instance object, which leads to the case of multiple singleton objects.
The problem-solving approach is also simple, using the Synchronized keyword:
Ii
1 classsingleton{2 Private StaticSingleton Singleton; 3 PrivateSingleton () {}4 5 Public Static synchronizedSingleton getinstance () {6 if(Singleton = =NULL){7Singleton =NewSingleton (); 18 }9 returnSingleton;Ten } One}
This solves the problem of multithreading concurrency, but it brings efficiency problems: Our goal is to create only one instance, that is, the//1 code will only be executed once, it is precisely this place need to synchronize, after the creation of the instance, singleton non-empty will directly return the object reference, Instead of having to do non-null validation in the synchronization code block each time. Then consider synchronizing only the//1:
③
1 classsingleton{2 Private StaticSingleton Singleton; 3 PrivateSingleton () {}4 5 Public StaticSingleton getinstance () {6 if(Singleton = =NULL){7 synchronized(Singleton.class){ 8Singleton =NewSingleton (); 19 }Ten } One returnSingleton; A } -}
This brings up the same problem as the first, when multiple threads are executing to a conditional judgment statement, and multiple instances are created. The problem is that when a thread creates an instance, singleton is no longer empty, but subsequent threads do not do a second non-empty check. Then it is clear that you should check again in the synchronous code block, which is called double detection:
④ Double detection:
1 classsingleton{2 Private StaticSingleton Singleton; 3 PrivateSingleton () {}4 5 Public StaticSingleton getinstance () {6 if(Singleton = =NULL){7 synchronized(Singleton.class){8 if(Singleton = =NULL)9Singleton =NewSingleton (); 1Ten } One } A returnSingleton; - } -}
It's been perfect here, and it doesn't look like a problem. But this double detection mechanism is problematic before JDK1.5, and the problem is in//1, caused by so-called unordered writes. In general, when initializing an object, it undergoes a series of operations, such as memory allocation, initialization, and the return of objects on the heap, and the resulting object is a complete object that can be used normally. But Java's unordered writes can cause the order to be reversed, that is, memory allocations, return object references, and the order in which they are initialized, in which case the corresponding to//1 is that Singleton is no longer null, but instead points to an object on the heap, but the object has not yet completed the initialization action. Unexpected problems arise when subsequent threads discover that Singleton is not null and is used directly.
After JDK1.5, you can use the volatile keyword to modify the variables to solve the problem of out-of-order writes, because an important role of the volatile keyword is to prohibit the ordering of instructions, that is, to ensure that memory allocations are not present, return object references, initialize the sequence, This makes double detection really work.
Of course, you can also choose not to use dual detection, and non-lazy loading to achieve the same effect:
1 class singleton{ 2 private static Singleton Singleton = new Singleton (); 3 private Singleton () {} 4 5 public< /span> static Singleton getinstance () { Span style= "COLOR: #008080" >6 return Singl Eton; 7 } 8 }
Reference
Double check lock problem in Java Singleton mode
Single-case mode and double detection
Double check in Java (double-check)
Java concurrency Programming: volatile keyword parsing
Java Concurrent notes--singleton and double detection