Single-Case mode

Source: Internet
Author: User

Today look at the design mode, a colleague took a single example of my implementation of the mode, I answered 2, one is "a Hungry man mode", one is "lazy mode" + double detection plus lock. But my colleague gave me another way to "enumerate the singleton", the individual has not been used, not very understanding, but from the enumeration thread security is no problem. So the internet to check the "enumeration", so the network to see the singleton mode of implementation of the method summarized.

Below from: http://wuchong.me/blog/2014/08/28/how-to-correctly-write-singleton-pattern/

Lazy, thread-safe

The simplest way to solve the above problem is to set the entire getinstance () method to synchronous (synchronized).

 Public Static synchronized Singleton getinstance () {    ifnull) {        new  Singleton ();    }     return instance;}

Although it is thread-safe and solves a multi-instance problem, it is not efficient. Because at any time only one thread can call the GetInstance () method. However, the synchronous operation only needs to be required on the first call, that is, when the singleton instance object is created for the first time. This leads to a double test lock.

Double Test lock

Double-check lock mode (double checked locking pattern) is a method of locking with a synchronous block. The programmer calls it a double-check lock because there will be two checks instance = = Null , one time outside the synchronization block, and one in the synchronization block. Why do I have to check again within the synchronization block? Because there may be multiple threads that go in and out of the synchronization block, multiple instances are generated if no two checks are made within the synchronization block.

 public  static   Singleton Getsingleton () { if  (instance = null ) {// single Checke D  synchronized  (Singleton.  Class   if  (instance = null ) {// double Checked             Instance = new   Singleton (); }}}  return   instance;}  

This piece of code looks perfect, unfortunately, it's problematic. The main reason is instance = new Singleton () , this is not an atomic operation, in fact in the JVM this sentence probably did the following 3 things.

    1. allocating memory to instance
    2. Call Singleton's constructor to initialize member variables
    3. Point the instance object to the allocated memory space (instance is non-null after performing this step)

However, there is an optimization of command reordering in the JVM's immediate compiler. In other words, the order of the second and third steps above is not guaranteed, and the final order of execution may be 1-3-2. If it is the latter, then after 3 execution, 2 is not executed, before the thread two is preempted, then instance is non-null (but not initialized), so the thread two will return directly to instance, then use, and then logically error.

We just need to declare the instance variable to be volatile.

 Public classSingleton {Private volatile StaticSingleton instance;//declared as volatile    PrivateSingleton () {} Public StaticSingleton Getsingleton () {if(Instance = =NULL) {                                     synchronized(Singleton.class) {                if(Instance = =NULL) {instance=NewSingleton (); }            }        }        returninstance; }   }

Some people think that the reason for using volatile is visibility, which is to ensure that the thread does not have a copy of instance locally, and each time it is read in the main memory. But it's not right, actually. The main reason for using volatile is another feature: Prohibit command reordering optimizations. That is, there is a memory barrier (generated assembly code) after the assignment operation of the volatile variable, and the read operation is not reordered before the memory barrier. For example above, the take operation must be executed after 1-2-3 or after the 1-3-2, there is no execution to 1-3 and then fetch the value of the case. From the perspective of the "first occurrence principle", it is that the write operation of a volatile variable takes precedence over the reading of the variable ("Back" is the order of time).

However, it is important to note that there is a problem with volatile double-check locks in versions prior to Java 5. The reason is that Java 5 JMM (Java memory model) is flawed, the immediate declaration of variables as volatile does not completely avoid reordering, mainly the volatile variable before and after the code still has a reordering problem. The issue of volatile masking reordering is fixed in Java 5, so it is safe to use volatile after this.

I believe you will not like this complex and implicit problem of the way, of course, we have a better way to implement a thread-safe single-case mode.

A hungry man type static final field

This approach is very simple because instances of Singleton are declared as static and final variables, initialized when the class is first loaded into memory, so creating the instance itself is thread safe.

 public  class   singleton{ //  Initializes the  private  static  
   
    final  Singleton instance = 
     Singleton        ();  
    private  
     Singleton () {}  
    public  
    static  
     Singleton getinstance () {     
    return  
     instance; }}
   

This kind of writing, if perfect, there is no need to nag so many double lock problem. The disadvantage is that it is not a lazy load mode (lazy initialization), and a single session is initialized at the beginning of the load class, even if the client does not call the GetInstance () method. The creation of a hungry man is not available in some scenarios: for example, if the creation of a Singleton instance is dependent on a parameter or configuration file, a method must be called before getinstance () to set the parameter to it, so that the singleton can not be used.

Static inner class static nested class

I prefer to use static inner class methods, which are recommended in effective Java.

 Public classSingleton {Private Static classSingletonholder {Private Static FinalSingleton INSTANCE =NewSingleton (); }      PrivateSingleton () {} Public Static FinalSingleton getinstance () {returnsingletonholder.instance; }  }

This notation still uses the JVM itself to ensure thread safety, because Singletonholder is private, there is no way to access it except for getinstance (), so it is lazy, it is not synchronized when the instance is read, there is no performance flaw; JDK version.

Enum enum

It's too easy to write a single example with an enumeration! This is also its greatest advantage. The following code is the usual way to declare an enumeration instance.

 Public enum easysingleton{    INSTANCE;}

We can access the instance through Easysingleton.instance, which is much simpler than calling the GetInstance () method. Creating an enumeration is thread-safe by default, so there is no need to worry about double checked locking, and it can prevent deserialization from causing new objects to be recreated. But it is rare to see someone write like this, perhaps because they are not familiar with it.

Summarize

In general, there are five types of patterns in a singleton: lazy, a hungry man, double-check lock, Static inner class, enumeration. All of this is a thread-safe implementation.

As far as I am concerned, the normal use of the A Hungry man-style is good, if the explicit requirement to lazy loading (lazy initialization) will tend to use static inner class, if it involves the deserialization of creating an object, try to use enumerations to implement the Singleton.

--------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------- -------------------------------------------

Why enumeration is better in singleton mode

Enumeration Singleton (enum Singleton) is a new way to implement the singleton pattern, although the singleton pattern has been in Java for a long time, but the enumeration singleton is relatively new concept, enumeration this feature is in the Java5 only appears, This article focuses on why we should use enumerations to implement a singleton pattern, and what are the advantages compared to a singleton pattern implemented in the traditional way?

1. Simple enumeration notation

Simple notation This is its greatest advantage, if you have previously written a singleton pattern, you should know that even if there is a DCL (double checked locking) may also create more than one instance, Although the problem is fixed in JAVA5 (jdk1.5 has made a lot of improvements in the memory model, providing the volatile keyword to modify the variable), it is still tricky for the novice. Comparing synchronization with double checked locking, enumerating the singleton that is simply too simple. If you don't believe that, then compare the following code with the traditional singleton and enumeration singleton implemented with double checked locking.

Enumeration implementations:

The following code is the usual practice of declaring an enumeration instance, and it may also contain instance variables and instance methods, but for simplicity I'm not using these things, just be careful if you're using an instance method, then you need to make sure that thread is safe (if it affects the state of other objects). The creation of the default enumeration instance is thread-safe, but any other method in the enumeration is the responsibility of the programmer.

/** * Singleton Pattern example using Java enumj */  Public enum easysingleton{    INSTANCE;}

You can access it through easysingleton.instance, which is much simpler than calling the GetInstance () method.

Double checked Locking implementation method:

The following code is a single example implemented with the double checked locking method, where the getinstance () method is checked two times to ensure that the instance instance is null or has been instantiated, which is why it is called a double checked Locking mode.

/*** Singleton Pattern example with Double checked Locking*/ Public classdoublecheckedlockingsingleton{Private volatileDoublecheckedlockingsingleton INSTANCE; PrivateDoublecheckedlockingsingleton () {} PublicDoublecheckedlockingsingleton getinstance () {if(INSTANCE = =NULL){            synchronized(Doublecheckedlockingsingleton.class){                //Double checking Singleton instance                if(INSTANCE = =NULL) {INSTANCE=NewDoublecheckedlockingsingleton (); }            }         }         returnINSTANCE; }}

You can use Doublecheckedlockingsingleton.getinstance () to get an instance.

From the creation of a lazy loaded Thread-safe singleton, its number of lines of code is the same as the enumeration, which can all be done in one line, because the singleton created by the enumeration also guarantees that the instance is thread-safe at the JVM level.

One might argue that there is a better way to write a singleton to replace the duoble checked locking method, but each method has his own merits and demerits, as I would most likely initialize a static field through a class, as shown below, but remember that he is not a singleton in lazy loaded form.

Static Factory Implementation Method:

This is one of my favorite ways to implement Singleton mode because the Singleton is a static final variable that is initialized when the class is first loaded into memory, so the instance created is Thread-safe.

/*** Singleton Pattern example with static Factory method*/  Public classsingleton{//initailzed during class loading    Private Static FinalSingleton INSTANCE =NewSingleton (); //To prevent creating another instance of Singleton    PrivateSingleton () {} Public StaticSingleton Getsingleton () {returnINSTANCE; }}

You can call Singleton.getsingleton () to get the instance.

2. Enumerate your own processing of serialization

Another problem with the traditional singleton is that once you implement the serialization interface, they no longer keep the singleton, because the ReadObject () method always returns a new object Just like Java constructs, you can avoid this by using the Readresolve () method. Look at the following example:

// Readresolve To prevent another instance of Singleton Private Object readresolve () {    return  INSTANCE;}

This can even be more complicated if your singleton class maintains the state of other objects, so you need to make them transient objects. However, the JVM is guaranteed to serialize, but the enumeration is a singleton.

3. Enumeration instance creation is Thread-safe

As stated in the first article, because creating an enumeration is thread-safe by default, you do not have to worry about double checked locking.

Summary: Enumerations are guaranteed to be serialized and thread-safe, and as long as a few lines of code can be implemented as a single best practice, but you can still implement the singleton in other ways, but I still don't get a more convincing reason not to use enumerations. If you have any, you may as well tell me.

Single-Case mode

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.