Java Singleton mode for lazy loading issues

Source: Internet
Author: User

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

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.