Explore Design Patterns----Single-instance mode

Source: Internet
Author: User

The singleton mode can be very simple, and all it needs is one class to complete. However, the singleton pattern can be quite complex if the number of objects created and when they are created is taken seriously.

The structure is simple, but we also have some small requirements as follows:

1. Most basic requirements: each time from getinstance () can return one and only one object.
2. Slightly higher requirements: I hope this method can adapt to multi-threaded concurrent access.
3. One more requirement: The method performs as high as possible.
4. The final requirement is that lazy loading (lazy load) is desired and is constructed when needed.

Purpose : You want an object to create only one instance and provide a global access point.

The first time we wrote the Singleton pattern was the following:

public class Singletonkerrigana {         /**      * Singleton object instance *      /      private static Singletonkerrigana instance = null;         public static Singletonkerrigana getinstance () {          if (instance = = null) {                              //line A              instance = new Singletonkerr Igana ();          Line B          }          return instance;      }  }  

This writing we put four point requirements from the top down detection, found that the 2nd time there is a problem, assuming such a scenario: two threads concurrent call Singletonkerrigana.getinstance (), assuming that the line Cheng first determine whether instance is null, Line A in the code enters the position of line B. As soon as the decision is complete, the JVM switches the CPU resources to thread two, and because the line Cheng has not yet executed lines B, instance is still empty, so thread two executes the new Signletonkerrigana () operation. After a moment, the line Cheng is re-awakened, it is still performing the new Signletonkerrigana () operation, OK, the question comes, two Kerrigan who is Li Kui who is the Lee ghost?

Next, we do a second attempt at the singleton pattern:

public class Singletonkerriganb {         /**      * Singleton object instance *      /      private static SINGLETONKERRIGANB instance = null;         Public synchronized static SINGLETONKERRIGANB getinstance () {          if (instance = = null) {              instance = new Singletonkerr IGANB ();          }          return instance;      }  }  

There is a synchronized modifier in the method compared to the first code, and it is now guaranteed that there is no thread problem. But there's a big (at least time-consuming) performance problem here. In addition to executing the SINGLETONKERRIGANB constructor for the first call, each subsequent call returns the instance object directly. Returning an object this is a time-consuming operation, with most of the time spent on the synchronized modifier's synchronous preparation, which is therefore not a cost-effective performance.

Then continue to change the code to look like this:

public class Singletonkerriganc {         /**      * Singleton object instance *      /      private static Singletonkerriganc instance = null;         public static Singletonkerriganc getinstance () {          synchronized (singletonkerriganc.class) {              if (instance = = NULL {                  instance = new Singletonkerriganc ();}          }          return instance;      }  }  

Basically, it doesn't make sense to move synchronized to the inside of the code, each time you call getinstance () or synchronize. The synchronization itself is not a problem, but we only want to synchronize the first time we create the Kerrigan instance, so we have the following notation-double lock check (DCL).

public class Singletonkerrigand {         /**      * Singleton object instance *      /      private static Singletonkerrigand instance = null;         public static Singletonkerrigand getinstance () {          if (instance = = null) {              synchronized (singletonkerrigand.class {                  if (instance = = null) {                      instance = new Singletonkerrigand ();          }}} return instance;      }  }  

It seems that this has reached our requirement that, in addition to the first creation of an object, the other accesses are returned in the first if, and therefore do not go to the synchronization block. Is it perfect?

Let's take a look at this scenario: assuming that the thread executes to instance = new Singletonkerrigand (), it looks like a sentence, but in fact it's not an atomic operation (atomic manipulation means that the statement is either executed or not executed, It is not possible to perform half of this scenario). In fact, there are many non-atomic operations in high-level languages, and we just have to look at the corresponding assembly code that was compiled and executed in the JVM, and this sentence was compiled into 8 assembly instructions, roughly doing 3 things:

1. Allocates memory to an instance of Kerrigan.
2. Initialize the Kerrigan constructor
3. Point the instance object to the allocated memory space (note that this step instance is not null)

However, because the Java compiler allows the processor to execute in a random order (Out-of-order), and JDK1.5 jmm (Java Memory Medel) before the cache, register to the main memory write-back order of the provisions, the above 2nd and 3rd order is not guaranteed, That is, the execution order may be 1-3-2, if it is the latter, and after 3 execution, 2 is not executed, is switched to the thread two, this time instance because it has been in line one to execute the 3rd, instance is already non-empty, So thread two take instance directly, then use, and then logically error, and this difficult to track difficult to reproduce errors estimated that the debugging last week may not be able to find out, is really a coffee table cup.

It is not entirely true that the DCL is written in a form that is recommended in a number of technical books, textbooks (including books based on JDK1.4 versions). It is true that the DCL is feasible in some languages, such as the C language, depending on whether the order of 2, 3 steps is guaranteed. After JDK1.5, the authorities have noticed this issue, so the JMM is adjusted and the volatile keyword is materialized, so if the JDK is a 1.5 or later version, you only need to change the definition of instance to "private volatile static Singletonkerrigand instance = null; " It is guaranteed that every time the instance is read from the main memory, it is possible to use the DCL notation to complete the singleton mode. Of course, volatile is more or less likely to affect performance, and most importantly we have to consider JDK1.42 as well as previous versions, so the improvement of the single-instance pattern in this article continues.

A class will only be initialized once in a ClassLoader, which is guaranteed by the JVM itself, so throw the initialized instance to the JVM, and the code is changed to this:

public class Singletonkerrigane {         /**      * Singleton object instance *      /      private static Singletonkerrigane instance = new Singletonkerrigane ();         public static Singletonkerrigane getinstance () {          return instance;      }  }  

Well, if the writing is perfect, then there are a couple of words in front of the writers who are entertaining readers. This type of writing does not occur concurrency problems, but it is a hungry man-style, after ClassLoader loaded class Kerrigan instance will be created the first time, a hungry man style of creation in some scenarios will not be used: for example, the creation of Kerrigan instance is dependent parameters or configuration file, You must call a method before getinstance () to set the parameter to it, so that the single-instance notation cannot be used.

Let's take a look at one of the following examples of how I think I can handle more scenarios:

public class SINGLETONKERRIGANF {         private static class Singletonholder {          /**          * Singleton object instance *          /          static Final singletonkerriganf INSTANCE = new singletonkerriganf ();      }         public static singletonkerriganf getinstance () {          return singletonholder.instance;      }  }  

This notation still uses the JVM itself to ensure thread safety, and since Singletonholder is private, there is no way to access it except for getinstance (), so it is lazy, and does not synchronize while reading instances, no performance flaws , and does not rely on JDK versions.

Through the attempt to understand the advantages and disadvantages of the various implementations of the singleton pattern. The double lock lock detection is discussed in a simple way, so we can understand why the singleton pattern is the simplest and most complicated one in the course of the evolution of various attempts.

Finally, we compare the pros and cons of lazy mode and a hungry man mode:

Lazy mode, which is characterized by the slow speed at which objects are obtained at runtime, but faster when loading classes. It consumes resources only a fraction of the time throughout the application's life cycle.
A hungry man mode, which is characterized by the slow loading of the class, but the speed at which the object is obtained at runtime is relatively fast. It always consumes resources from the time it is loaded to the end of the app.


These two modes are very quick to initialize, the lightweight object that consumes less resources, there is not much performance difference, choose the lazy or a hungry man-style is no problem. However, for slow initialization, heavy-resource-intensive objects, there will be more obvious differences. Therefore, the A hungry man mode is applied to the heavyweight object, the class loads slowly, but the run time is fast; in contrast to lazy mode, the class loads faster, but the first time the runtime gets the object is slow.
From the user experience point of view, we should prefer a hungry man mode. We are willing to wait for a program to take a long time to initialize, but do not like to wait too long while the program is running, giving people a feeling of insensitivity, so we recommend using a hungry man mode for single-instance mode with heavyweight object participation.



Explore Design Patterns----Single-instance 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.