Look at the Java design pattern-a single example of "Go"

Source: Internet
Author: User

Singleton mode Everyone is not unfamiliar, also know that it is divided into why lazy, a hungry man-style and so on. But is your understanding of the singleton pattern thorough enough? Today I take you to look at my eyes of the singleton, may be different from your understanding.

Here's a simple little example:

[Java] View plaincopyprint?
  1. Simple lazy Type
  2. Public class Singleton {
  3. // Singleton case variable
  4. private static Singleton instance = null;
  5. //privatization of construction methods to ensure that external classes cannot be instantiated by constructors
  6. Private Singleton () {}
  7. //Get an instance of a singleton object
  8. public static Singleton getinstance () {
  9. if (instance = = null) {
  10. Instance = new Singleton ();
  11. }
  12. System.out.println ("I am a simple lazy type single case!  ");
  13. return instance;
  14. }
  15. }


It is easy to see that the above code in the case of multithreading is not safe, when two threads into if (instance = = null), two threads are judged to be empty, and then get two instances. This is not the single case we want.

Next we use the locking method to implement mutual exclusion, so as to ensure the implementation of the Singleton.

[Java] View plaincopyprint?
  1. Synchronous Lazy-way
  2. Public class Singleton {
  3. // Singleton case variable
  4. private static Singleton instance = null;
  5. //privatization of construction methods to ensure that external classes cannot be instantiated by constructors
  6. Private Singleton () {}
  7. //Get an instance of a singleton object
  8. public static synchronized Singleton getinstance () {
  9. if (instance = = null) {
  10. Instance = new Singleton ();
  11. }
  12. System.out.println ("I am a synchronous lazy type single case!  ");
  13. return instance;
  14. }
  15. }

Adding synchronized does ensure thread safety, but is this the best way to do it? Obviously it is not, because in this way every call to the getinstance () method is locked, and we just need to lock on the first call to GetInstance (). This obviously affects the performance of our program. We continue to look for better ways.

After analysis, it is only necessary to ensure that instance = new Singleton () is thread-mutually exclusive to ensure thread safety, so there is the following version:

[Java] View plaincopyprint?
  1. Double Locking lazy type
  2. Public class Singleton {
  3. // Singleton case variable
  4. private static Singleton instance = null;
  5. //privatization of construction methods to ensure that external classes cannot be instantiated by constructors
  6. Private Singleton () {}
  7. //Get an instance of a singleton object
  8. public static Singleton getinstance () {
  9. if (instance = = null) {
  10. synchronized (Singleton. Class) {
  11. if (instance = = null) {
  12. Instance = new Singleton ();
  13. }
  14. }
  15. }
  16. System.out.println ("I am a double lock lazy-type single case!  ");
  17. return instance;
  18. }
  19. }

This time it seems to solve the thread-safety problem, and not every call to getinstance () will lock down and cause performance degradation. Looks like a perfect solution, actually?

Unfortunately, the facts are not so perfect as we think. There is a mechanism in the Java Platform memory model called "unordered write" (Out-of-order writes). It is this mechanism that causes the failure of the double-check locking method. The key to this question is on line 5th of the above code: instance = new Singleton (); This line actually did two things: 1, called the constructor method, created an instance. 2. Assign this instance to the instance instance variable. The problem is that these two-step JVMs are not guaranteed to be sequential. Other words. It is possible that the instance has been set to non-empty before the constructor method is called. Let's take a look at the following:

Suppose there are two threads a, B

1. Thread A enters the getinstance () method.

2, because at this time instance is empty, so thread a enters synchronized block.

3. Thread A executes instance = new Singleton (); Set the instance variable instance to non-null. (Note that it is before the constructor method is called.) )

4, thread A exits, thread B enters.

5. Thread B Checks if instance is empty and is not empty at this time (the third step is set to non-null by thread a). Thread B Returns a reference to instance. (The problem arises when the instance reference is not an instance of singleton because the constructor method is not called.) )

6, thread B exits, thread a enters.

7, thread A continues to call the construction method, completes the initialization of the instance, and then returns.

Isn't there a good way to do it? There must be a good way, we continue to explore!

[Java] View plaincopyprint?
  1. Solving unordered writing problems lazy style
  2. Public class Singleton {
  3. // Singleton case variable
  4. private static Singleton instance = null;
  5. //privatization of construction methods to ensure that external classes cannot be instantiated by constructors
  6. Private Singleton () {}
  7. //Get an instance of a singleton object
  8. public static Singleton getinstance () {
  9. if (instance = = null) {
  10. synchronized (Singleton. Class) { //1
  11. Singleton temp = instance; //2
  12. if (temp = = null) {
  13. synchronized (Singleton. Class) { //3
  14. temp = new Singleton (); //4
  15. }
  16. instance = temp; //5
  17. }
  18. }
  19. }
  20. System.out.println ("I am the one who solves the disordered writing of lazy-type singleton!"  ");
  21. return instance;
  22. }
  23. }


1. Thread A enters the getinstance () method.

2. Because instance is empty, thread A enters the first synchronized block of position//1.

3. Thread A executes the code of Location//2 and assigns the instance to the local variable temp. Instance is empty, so temp is also empty.

4, because temp is empty, thread A enters the second synchronized block of position//3. (later think of this lock a bit redundant)

5, thread A execution location//4 code, the TEMP is set to non-empty, but has not yet called the construction Method! ("unordered write" issue)

6. If thread A is blocked, thread B enters the getinstance () method.

7, because instance is empty, thread B tries to enter the first synchronized block. But because thread a is already inside. So I can't get in. Thread B is blocked.

8. Thread A activates, and continues executing the code for location//4. Call the constructor method. Build the instance.

9. Assign the instance reference of temp to instance. Exit two synchronized blocks. Returns an instance.

10, thread B activated, enter the first synchronized block.

11, thread B executes the code of the location//2, assigns the instance instance to the TEMP local variable.

12, thread B determines that the local variable temp is not empty, so skip the IF block. Returns a instance instance.

So far, the above problem is solved, but we suddenly found that in order to solve the problem of thread safety, but give people feel like a lot of yarn wrapped around .... Messy, so we need to streamline:

[Java] View plaincopyprint?
  1. A Hungry man type
  2. Public class Singleton {
  3. //Singleton variable, static, initialized at class load time, ensure thread safety
  4. private static Singleton instance = new Singleton ();
  5. //Privatization method to ensure that external classes cannot be instantiated by constructors.
  6. Private Singleton () {}
  7. //Get an instance of a singleton object
  8. public static Singleton getinstance () {
  9. System.out.println ("I am the A Hungry man type single case!  ");
  10. return instance;
  11. }
  12. }

See the above code, instantly feel the world is quiet. However, this approach is the A hungry man method, that is, the pre-declaration of singleton objects, which brings a disadvantage is: if the construction of the single case is very large, the construction and delay in use, will lead to waste of resources.

Is there a perfect way? Keep looking:

[Java] View plaincopyprint?  
  1. Inner class implements lazy-type
  2. Public class Singleton {
  3. private static class singletonholder{
  4. //single-case variable
  5. private static Singleton instance = new Singleton ();
  6. }
  7. //Privatization method to ensure that external classes cannot be instantiated by constructors.
  8. Private Singleton () {
  9. }
  10. //Get an instance of a singleton object
  11. public static Singleton getinstance () {
  12. System.out.println ("I am an internal class singleton!  ");
  13. return singletonholder.instance;
  14. }
  15. }

Lazy (avoid the waste of resources above), thread-safe, simple code. Because the Java mechanism specifies that the inner class Singletonholder be loaded (and lazy) only when the getinstance () method is first called, and that the loading process is thread-safe (thread-safe). An instance is instantiated once when the inner class is loaded.

Simply say the above-mentioned unordered write, which is a feature of the JVM, such as declaring two variables, String A; String b; The JVM may load a or B first. In the same vein, instance = new Singleton (), the instance may be set to non-empty before calling the Singleton constructor. This is a lot of people will have doubts, said has not yet instantiated a singleton object, then instance how to become non-empty it? What is the value of it now? To understand this problem, you need to understand instance = new Singleton (); How is this sentence executed, the following with a pseudo-code to explain to you:

[Plain] View plaincopyprint?
    1. MEM = allocate (); Allocates memory for the singleton object.
    2. instance = mem; Note that the instance is now non-empty, but it has not been initialized yet.
    3. Ctorsingleton (instance); Call Singleton's constructor, passing instance.

This shows when a thread executes to instance = mem; When instance is non-empty, if another thread enters the program to determine that instance is non-null, then jumps directly to return instance, and Singleton's construction method has not yet called instance, now the value is allocate (); Returns the Memory object. So the second thread gets not an object of singleton, but a memory object.

Look at the Java design pattern-a single example of "Go"

Related Article

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.