Design Patterns
The first thing to do is to explain what lazy loading is, delay loading is to wait until the real use of the time to create the instance, not to create.
From the angle of speed and reaction time, non-delayed loading (also known as a Hungry man) is good; from the resource utilization efficiency, lazy loading (also known as lazy-type) is good.
Here are a few common examples of how to design a single example:
First : non-lazy loading of singleton classes
Java code
Public class Singleton { private Singleton () {} privatestaticfinal New Singleton (); Public Static Singleton getinstance () { return instance; } }
second type : synchronous lazy Loading
Java code
Public classSingleton {Private StaticSingleton instance =NULL; PrivateSingleton () {} Public Static synchronizedSingleton getinstance () {if(Instance = =NULL) {instance=NewSingleton (); } returninstance; } }
The third type : Dual detection synchronous delay loading
In order to deal with the original non-lazy loading method bottleneck, we need to check the instance for a second time to avoid excessive synchronization (because the synchronization here only needs to be synchronized when the instance is first created, and once it is created, it does not need to acquire the lock when the instance is acquired), but it does not work in Java. Because if (instance = = null) Outside of the synchronization block, you may see an instance that already exists but is not complete. JDK5.0 later versions are possible if instance is volatile:
Java code
Public classSingleton {Private volatile StaticSingleton instance =NULL; PrivateSingleton () {} Public StaticSingleton getinstance () {if(Instance = =NULL) { synchronized(Singleton.class) {//1 if(Instance = =NULL) {//2Instance =NewSingleton ();//3 } } } returninstance; } }
The problem of double detection locking failure is not attributed to the implementation bug in the JVM, but rather to the Java platform memory model. The memory model allows so-called "unordered writes", which is also a major cause of failure.
unordered Write :
To explain the problem, you need to re-examine the//3 lines in the list above. This line of code creates a Singleton object and initializes the variable instance to reference the object. The problem with this line of code is that, before the Singleton constructor body executes, the variable instance may become non-null, that is, the assignment statement is called before the object is instantiated, at which point the other thread gets an object that is also initialized, which causes the system to crash.
What the? This may have been unexpected, but it is true. Before explaining how this happens, please accept this fact for the first time, and let's examine how the double-check lock is broken. Assume that the code executes the following sequence of events:
1, thread 1 into the getinstance () method.
2, because instance is null, thread 1 enters synchronized block at//1.
3, Thread 1 advances to//3, but makes the instance non-null before the constructor executes.
4. Thread 1 is pre-occupied by thread 2.
5, Thread 2 checks if the instance is null. Because the instance is not NULL, thread 2 Returns the instance reference to a Singleton object that is constructed intact but partially initialized.
6. Thread 2 is pre-occupied by thread 1.
7, thread 1 completes the initialization of the object by running the constructor of the Singleton object and returning the reference to it.
To demonstrate the occurrence of this event, assume that the code line instance =new Singleton (); The following pseudo-code was executed:
MEM = allocate (); Allocates memory space for a singleton object.
instance = mem; Note that the instance reference is now non-null but not yet initialized
Ctorsingleton (instance); Calling constructors for Singleton objects through instance
This pseudo-code is not only possible, but is actually happening on some JIT compilers. The order of execution is reversed, but given the current memory model, this is also allowed to occur. This line of the JIT compiler is just a matter of academic practice for locking double checks.
If this article is really like this:http://dev.csdn.net/author/axman/4c46d233b388419e9d8b025a3c507b17.html said, 1.2 or later versions will not have a problem, but this rule is JMM specification? Who can confirm it.
Indeed, before JAVA2 (starting with jdk1.2), the instance fields are read and written directly to the main storage area . So when a thread allocates space for resource,
When you initialize and invoke a construction method, it is possible to allocate space actions in other threads that are visible, while the initialize and invoke construction methods are not yet complete.
However, since JAVA2, the JMM has undergone a fundamental change, allocating space, initializing, calling the construction method only to complete the working store of the thread, without
When you copy assignments to the primary store, the process is absolutely not visible to other threads. And this field is copied to the main memory area of the process, and there is no space allocated after
There is no possibility of initializing or calling a constructor method. In Java, everything is copied by the value referenced. Synchronizing to the primary store is actually the thread that's working
This constructed object of the store has a compressed heap address value that is copied to the primary store. This process is for other threads, either resource
Is null, or is a complete object. Never put an object that has been allocated space but not constructed so that other threads are visible.
Another detailed analysis article:http://www.iteye.com/topic/260515
Fourth : double detection with threadlocal repair
With Threadlocal, the critical resource (the resource that needs to be synchronized) is localized, specifically in this case, the first layer detection condition of the double detection if (instance = = NULL) is converted to the thread local scope. The threadlocal is also used only as a marker to indicate whether each thread has been visited, and if so, it is no longer necessary to walk the synchronization block, which increases the efficiency. But threadlocal was slower in versions before 1.4, but it was safe compared to volatile.
Java code
Public classSingleton {Private Static FinalThreadLocal perthreadinstance =NewThreadLocal (); Private StaticSingleton Singleton; PrivateSingleton () {} Public StaticSingleton getinstance () {if(Perthreadinstance.get () = =NULL){ //each thread will be called the first timeCreateInstance (); } returnSingleton; } Private Static Final voidCreateInstance () {synchronized(Singleton.class) { if(Singleton = =NULL) {Singleton=NewSingleton (); }} perthreadinstance.set (Perthreadinstance); } }
Fifth : Lazy loading using internal classes
In order to really delay the load, double detection in Java is not feasible, so only with the help of another class loading plus lazy loading:
Java code
Public classSingleton {PrivateSingleton () {} Public Static classHolder {//There 's no point in being private here. /*Private*/StaticSingleton instance =NewSingleton (); } Public StaticSingleton getinstance () {//private variables that the perimeter class can access directly to the inner class (whether static or not) returnholder.instance; } }
Single-Instance Testing
The following is a framework for testing a single case, with a classloader and reflection.
Note, in order to test whether the single is true, I wrote a class loader, and its parent loader is set to the root loader, so that singleton is loaded by Myclassloader, if not set to the root loader as the parent loader, the default is the system loader, Then the singleton will be loaded by the system loader, but we cannot unload the ClassLoader, and if loading the singleton ClassLoader does not unload, then the second time you cannot reload the singleton class. This class cannot be loaded and eventually causes the static variables in the singleton class to be reinitialized so that they cannot be tested.
The following test class deferred loading results are feasible and can also be used for other singleton tests:
Java code
Public classSingleton {PrivateSingleton () {} Public Static classHolder {//There 's no point in being private here. /*Private*/StaticSingleton instance =NewSingleton (); } Public StaticSingleton getinstance () {//private variables that the perimeter class can access directly to the inner class (whether static or not) returnholder.instance; } } classCreateThreadextendsThread {Object singleton; ClassLoader cl; PublicCreateThread (ClassLoader cl) { This. CL =cl; } Public voidrun () {Class C; Try{C= Cl.loadclass ("Singleton"); //when classes in two different namespaces are not visible to each other, the reflection mechanism can be used to access the properties and methods of the other instance.Method m = C.getmethod ("getinstance",Newclass[] {}); //when a static method is called, the first argument passed is a class objectSingleton = M.invoke (c,Newobject[] {}); C=NULL; CL=NULL; } Catch(Exception e) {e.printstacktrace (); } } } classMyclassloaderextendsClassLoader {PrivateString LoadPath; Myclassloader (ClassLoader cl) {Super(CL); } Public voidSetPath (String path) { This. LoadPath =path; } protectedClass Findclass (String className)throwsclassnotfoundexception {fileinputstream fis=NULL; byte[] data =NULL; Bytearrayoutputstream BAOs=NULL; Try{FIS=NewFileInputStream (NewFile (LoadPath+ classname.replaceall ("\ \", "\\\\") + ". Class")); BAOs=NewBytearrayoutputstream (); intTmpbyte = 0; while((Tmpbyte = Fis.read ())! =-1) {baos.write (tmpbyte); } Data=Baos.tobytearray (); } Catch(IOException e) {Throw NewClassNotFoundException ("Class is not found:" +ClassName, E); } finally { Try { if(FIS! =NULL) {fis.close (); } if(FIS! =NULL) {baos.close (); } } Catch(Exception e) {e.printstacktrace (); } } returnDefineClass (className, data, 0, data.length); } } classSingletest { Public Static voidMain (string[] args)throwsException { while(true) { //cannot let the system loader become the parent loader directly or indirectlyMyclassloader loader =NewMyclassloader (NULL); Loader. SetPath ("D:\\hw\\xcallc16b125spc003_js\\uniportal\\service\\aaa\\bin\\"); CreateThread Ct1=NewCreateThread (loader); CreateThread Ct2=NewCreateThread (loader); Ct1.start (); Ct2.start (); Ct1.join (); Ct2.join (); if(Ct1.singleton! =Ct2.singleton) {System.out.println (Ct1.singleton+ " " +Ct2.singleton); } //System.out.println (Ct1.singleton + "" + Ct2.singleton); Ct1.singleton =NULL; Ct2.singleton=NULL; Thread.yield (); } } }
Java singleton mode for lazy loading issues