Goku mode-java-single case mode

Source: Internet
Author: User
Tags volatile

"That mountain, just on the top, there is a fairy stone." Its stone has three Zhang six feet five inches tall, has two Zhang four feet circumference round. Three Zhang Six feet five inches high, according to the week 365 degrees, two Zhang four feet round, according to the political calendar 24 gas. There are nine eight holes in the body, press nine gossip. Surrounded by trees, there is no shade, there is a garden-lined. Cover since the opening up, every naïve show, day fine Yuet Wah, sense of a long time, then have the meaning of well-informed. Inside the bursting, one day, the production of a stone eggs, like a large ball-like. Because see the wind, turned into a stone monkey, the features are prepared, all limbs. He learned to learn to walk, to worship the quartet. Eye transport two Golden, shoot the house. 】

The above text describes the scene of Goku at birth. Monkey King only one, any program to use the Monkey King this object, can only use the same instance.

So, the singleton pattern is very well understood, the singleton pattern ensures that a class has only one instance, and this class creates its own unique instance and provides this instance to the entire system, which is called a singleton class.

In fact, this design pattern does not have much to do with abstract thinking or business architecture design, it requires understanding of the Java memory model and concurrent programming, so before introducing the singleton mode, we need to introduce the basic knowledge of JMM (Java memory model). Then it would be much simpler to understand the singleton pattern.

1. Re-order

In order to improve performance, the compiler and processor often reorder the instructions when executing the program. Reordering also includes compiler-optimized reordering, instruction-level parallelism, and the reordering of memory systems.

For example, the following section of code:

int a = 1; //a int b = 2; //b

A is not necessarily more than B, and their order of execution may be a-a, or b-a, or perhaps even executed together.

2.happens-before and As-if-serial

As-if-serial guarantees that the execution of a single-threaded program is not changed, and it gives the programmer an illusion that a single-threaded program executes in the order of the programs;

Happens-before ensures that the execution results of correctly synchronized multithreaded programs are not changed, and it gives the programmer an illusion that the correct synchronization of multithreaded procedures is performed in the order specified by Happens-before.

The programmer does not really care whether the two instructions are actually reordered, we only care about the semantics of the program execution can not be changed, that is, the execution results of the program can not be changed.

For example, the above code of the Order of A and b reversed, to the results of the program does not affect, we can still get two of the correct assignment of int variable. But if it's the following code, there's a problem:

int x = 1; // A int x = 2; // B

If the order of execution of the two lines of code changes, then the value of the x we finally get may not be 2, but 1, so the execution of the program has changed. Fortunately, JMM has been banned for this sort of data dependency (two instructions are all for the same variable), so we don't need to worry about it.

3. Class initialization lock

The Java language Specification specifies that for each class or interface A, there is a unique initial lock of la corresponding to it. The mapping from A to LA is implemented freely by the specific implementation of the JVM. The JVM acquires this initialization lock during class initialization, and each thread acquires at least one lock to ensure that the class has been initialized. This lock synchronizes the initialization of multiple threads to the same class .

4.volatile of Memory semantics

When a volatile variable is written, jmm flushes the shared variable value in the local memory corresponding to the thread to main memory, and when a volatile variable is read, JMM will invalidate the local memory for that thread, and the thread will then read the shared variable from main memory.

5.jsr-133 memory model

Starting with JDK5 , Java upgraded the memory model and started using the JSR-133 memory model. There are two major fixes to the old memory model: enhanced volatile memory semantics, strict JSR-133 of volatile variables and ordinary variables (the old memory model allows volatile variables to be reordered with ordinary variables), and enhanced final memory semantics, Make final have initialization security, in the old memory model, the value of reading the same final variable multiple times may be different.

Let's start by looking at the various implementations of the singleton pattern, perhaps you are not familiar with the above concepts, but the combination of specific code, I believe it will deepen your understanding.

A Hungry man mode

 Package Com.tirion.design.singleton;  Public class WuKong {    privatestaticnew  WuKong ();     Private WuKong () {    }    publicstatic  WuKong Getwukong () {          return  WuKong;}    }

The static variable is initialized when the class is loaded, and note that the construction method is also declared private, and we can only get the unique instance of Wukong by Wukong.getwukong () wukong static variable.

Since the implementation of the Singleton is done at the time the class is loaded, and regardless of whether the subsequent object instance is actually used (Wukong.getwukong () will not be executed), the object instance has been created, so it becomes the A Hungry man mode in a space-time-changing way.

The pros and cons of the A hungry man pattern are also obvious, and it does not have to wait for the time to be used to create the instance, saving the program's run time, but in some cases it may create unnecessary objects, resulting in wasted space.

Lazy mode

 PackageCom.tirion.design.singleton; Public classWuKong {Private StaticWuKong WuKong =NULL; PrivateWuKong () {} Public Static synchronizedWuKong Getwukong () {if(WuKong = =NULL) {WuKong=NewWuKong (); }        returnWuKong; }}

The lazy mode differs from the A Hungry man mode in that the creation of the instance object is placed inside the static factory method, and when the call to Wukong.getwukong () is made, the instance is determined to be created, and if it is not created, the initialization of the instance object is done, and the creation is returned directly.

Lazy mode in order to achieve thread safety in multi-threaded environment, the method of creating an instance adds synchronized synchronization control, by the way, synchronized is the compiler by inserting monitorenter and monitorexit instructions to synchronize control, All threads calling the synchronized method are waiting to get the monitor object lock at Monitorenter, so the lazy mode is very inefficient in a competitive environment, which is why it is called the lazy mode.

A single case of the double check lock mechanism of DCL based on volatile

1  PackageCom.tirion.design.singleton;2 3  Public classWuKong {4     Private Static volatileWuKong WuKong =NULL;5 6     PrivateWuKong () {7     }8 9      Public StaticWuKong Getwukong () {Ten         if(WuKong = =NULL) { One             synchronized(WuKong.class) { A                 if(WuKong = =NULL) { -WuKong =NewWuKong (); -                 } the             } -         } -         returnWuKong; -     } +}

We found that the double lock check mechanism has several details that are changed compared to the lazy mode:

A. The synchronized of the static factory method has been removed, instead using a synchronous code block for control

B. Changed from a previous judgment object instance null to two judgments

C. Object instances add volatile keyword modifiers

Let's take a look at some of these details and see what these changes mean:

For the first change, we can see from the lazy model analysis that the efficiency of the synchronized method will be poor, in fact, in addition to the object instance has just been created and is being created in the period of time, the latter time for the synchronized synchronization lock competition is wasteful ( Because the object instance has already been established), this is done by first judging if (WuKong = = null) {synchronized ...}, which avoids all the competition for the synchronized synchronization lock after the object instance is created, greatly saving the code execution time, Increased efficiency;

For the second change, is the combination of the previous changes produced, imagine now there are two threads A and b at the same time into the Line9 (code line number) method, because they are the first two entry method, so they all through the Line10 object instance is empty judgment, entered the Line11 synchronous code block, Because only one thread can enter the synchronization code block at the same time, thread A obtains a monitor lock, enters the synchronization code block, and executes the initialization of the object instance, releasing the monitor lock when thread a exits the synchronization code block. At this point in the blocked state of the thread B will get to the monitor lock and into the synchronization code block, if there is no second instance object is empty judgment, thread B will also perform the initialization of the object instance, so that the Singleton mode object instance is initialized only once the principle;

For the third change, let's take a look at how the JVM executes Line13 's WuKong = new WuKong (), in fact, this line of code can be decomposed into the following three lines of pseudo-code:

Memory = allocate ();   // 1-memory space of the allocated object ctorinstance;  // 2-Initialize object wuKong = memory;       // 3-Set Wukong to point to the memory address just allocated

On some compilers, 2 and 3 of the above three lines of code may be reordered, since reordering does not affect the as-if-serial principle, which, after reordering, points the Wukong to an empty memory space address and then initializes the object on empty memory space.

In a single-threaded scenario, the above reordering does not affect the execution results of the program, but in a multithreaded environment, the following may occur:

When thread B has just entered LINE10 's is null judgment, thread A happens to have the object memory address assignment and object initialization reordered, when thread B sees that the object instance is not null (empty memory address, but not null), so thread B bypasses the synchronization code block directly. Directly returns an object that has not yet been initialized.

So how do we solve this problem? One way of thinking is to disallow object memory address point and object initialization reordering.

After JDK5 or later, Java started using the new JSR-133 memory model, which made an important fix to the old memory model, enhanced the memory semantics of the volatile keyword, and by adding a memory barrier, The re-ordering of volatile object initialization and memory address points is prohibited, thereby avoiding problems that may result from the above situation.

It is important to note that this solution works only in JDK5 and later.

A singleton based on class initialization

 package   Com.tirion.design.singleton;  public  class   WuKong { private      WuKong () {};  private  static  class   Wukongholder { public
     static  WuKong WuKong = new   WuKong ();  public  static   WuKong Getwukong () { return   Wukon    Gholder.wukong; }}

When calling Wukong.getwukong (), the Wukongholder will be initialized immediately, and when we have described class initialization, all threads will compete for a class initialization lock, so this initialization action is thread safe.

At the same time, after the first thread finishes initializing the class, releasing the class initialization lock, the second thread attempts to acquire the class initialization lock, and the Happens-before rule guarantees that the release of a lock must occur before the same lock is acquired. So the first thread that performs the initialization of the class before releasing the lock is visible to the thread that gets the same lock later.

Under the guarantee of the Happens-before rule, no matter wuKong WuKong = new WuKong (), what sort of reordering occurs inside the code is not visible to subsequent threads.

By comparing the single-case and class-initialization-based singleton with volatile double-check locking, we find that the implementation code of the class-based initialization scheme is more concise and convenient, and does not require much jmm knowledge.

However, the single-instance mode of the volatile DCL has an additional advantage in that it allows for deferred initialization of instances fields in addition to lazy initialization of static fields. Therefore, when you need to implement deferred initialization for instance fields, you can choose a singleton pattern based on the volatile double-check mechanism.

An enumeration-based singleton

 Package Com.tirion.design.singleton;  Public enum wukongenum {    WUKONG;     Private WuKong WuKong;     Private Wukongenum () {        new  WuKong ();    }      Public WuKong Getwukong () {        return  WuKong;    }}

Before we understand the enumeration-based singleton, we need to know that the compiler creates an inherited Java.lang.Enum class for us at the time of creating the enumeration, which we cannot interfere with, and this class looks like this

 Public class extends enum{       publicstaticfinal  wukongenum WUKONG;       ...  }

When calling Wukongenum.getwukong (), the compiler automatically generates a private construction method that will be executed, the object instance will be initialized, and the JVM will guarantee that it will initialize only once because the object instance is static final. In addition, enum implements the Serializable interface, so it also provides a serialization mechanism free of charge.

So, using enumerations to implement singleton patterns is concise, efficient, and secure.

Introduction to the singleton mode here, you can remember it as an Goku singleton mode .

If you think there's something wrong or inadequate in the article, please point it out in the comments section and hopefully this article will help you learn Java design patterns. Reprint Please specify, thank you.

For more information on design patterns, see the-java design mode in goku mode.

Goku mode-java-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.