Go: Deep Java single-case mode----absolute depth __java

Source: Internet
Author: User
Tags static class volatile java web
Absrtact: A single example in the game will often use, it reduces the number of objects allocated, that is, the number of new, each time the object is used, the object has been instantiated before the completion of. But the game server is often a multi-threaded environment, so a single case must also be thread-safe. Take a look at this article, you will understand a lot of the 23 design patterns in Gof, the single case pattern is a relatively simple one. Sometimes, however, the simpler things are, the more likely they are to become problematic. The following is a detailed discussion of a single example design pattern. The so-called singleton pattern, in simple terms, is to ensure that only one instance of a class exists throughout the application. Like the application in the Java Web, which provides a global variable, is useful for a wide variety of purposes, such as preserving global data and implementing global operations. 1. The simplest implementation first, the simplest implementation that can be thought of is to write the constructor of a class as private, so that other classes cannot instantiate the class, and then provide a static instance in the class and be able to return it to the consumer. This allows the user to use an instance of this class through this reference.
public class Singletonclass { 
  private static final Singletonclass instance = new Singletonclass (); 
  public static Singletonclass getinstance () {return 
    instance; 
  } 
  Private Singletonclass () { 
  }      
}
As in the previous example, if an external user needs to use an instance of Singletonclass, it can only pass through the getinstance () method, and its construction method is private, thus ensuring that only one object exists. 2. Performance optimization--lazy loaded The above code is simple, but there is a problem-whether or not this class is used, a instance object is created. If the creation process is time-consuming, such as the need to connect 10,000 databases (exaggerated ...:-)), and this class is not necessarily used, then the creation process is useless. How to do it. To solve this problem, we think of a new solution:
public class Singletonclass { 
  private static singletonclass instance = null; 
  public static Singletonclass getinstance () { 
    if (instance = null) { 
      instance = new Singletonclass (); 
    } 
    return instance; 
  } 
  Private Singletonclass () { 
  }     
}
The code changes in two places--first, initialize instance to null until it is first used to create an object by determining whether it is null. Because the creation process is not at the declaration, the final modification must be removed. Let's imagine the process. To use Singletonclass, call the GetInstance () method. The first time the instance was found to be null, then a new object was returned, and the second time, because the instance was static, it was not null, so the object would not be created and returned directly. This process becomes lazy loaded, or Changaca, which is not loaded until it is used. 3. Synchronizing the code above is clear and simple. However, like the famous saying, "80% of the errors are caused by 20% code optimization." Single-threaded, this code is not a problem, but if it is more than one thread, the trouble comes. Let's analyze this: thread A wants to use Singletonclass to invoke the GetInstance () method. Because it was the first call, a found that instance was null, so it started creating the instance, at which point the CPU took a time slice switch, thread B started, it wanted to use Singletonclass, called the GetInstance () method, Also detected instance is null--note, which is switched after a is detected, that is, a does not have time to create objects-so B starts creating. b After the creation is complete, switch to a to continue execution because it is already detected, so a will not be detected again, it will create the object directly. In this way, threads A and B each have a Singletonclass object--the single example fails. The solution is also very simple, that is lock:
public class Singletonclass { 
  private static singletonclass instance = null; 
  Public synchronized static Singletonclass getinstance () { 
    if (instance = = null) { 
      instance = new Singletonclass (); 
    } 
    return instance; 
  } 
  Private Singletonclass () {  
  }     
}
To getinstance () plus a sync lock, a thread must wait for another thread to be created to use this method, which guarantees the uniqueness of the single case. 4. The code is also very clear and simple, however, simple things are often not ideal. There is no doubt that this code has a problem with performance.--synchronized decorated synchronized blocks are several times slower than normal code snippets. If there are many calls to getinstance (), the performance problem has to be considered. Let's analyze whether the entire method must be locked, or just one of the sentences is enough to add a lock. Why do we have to lock it. Analyze the reasons for the appearance of lazy loaded. The reason is that null-detecting operations are separated from the operation that created the object. If these two operations can be done atomically, then the single example is guaranteed. So we started to modify the code:
public class Singletonclass { 
  private static singletonclass instance = null;  
  public static Singletonclass getinstance () { 
    synchronized (singletonclass.class) { 
      if (instance = null) { 
        Instance = new Singletonclass (); 
      } 
    }     
    return instance; 
  } 
  Private Singletonclass () { 
  } 
}
First, remove the synchronization of getinstance () and then load the sync lock on the IF statement. But such modifications do not work: because the getinstance () is necessarily synchronized every time it is invoked, there is a performance problem. If...... What if we were to determine if we were going to sync for null?
public class Singletonclass { 
  private static singletonclass instance = null; 
  public static Singletonclass getinstance () { 
    if (instance = null) { 
      synchronized (singletonclass.class) {
  if (Instance = = null) { 
          instance = new Singletonclass () 
        ; 
    }}} return instance; 
  } 
  Private Singletonclass () { 
  } 
}
Do you have any more questions? First, the instance is judged to be null, if NULL, the lock is initialized, and if not NULL, the instance is returned directly. This is the double-checked locking design implementation of the single example mode. So far, everything is perfect. We implemented the single case pattern in a very clever way. 5. From the source check below we start to say the principle of compiling. Compiling is the process of translating source code into target code-most of it refers to machine code. For Java, its target code is not local machine code, but virtual machine code. The compiler principle has a very important content in compiler optimization. compiler optimization means that, without changing the original semantics, the program can be run faster by adjusting the order of the statements. This process becomes reorder. You know, the JVM is just a standard, not an implementation. There is no provision in the JVM for compiler optimizations, that is, JVM implementations are free to perform compiler optimizations. Let's think about what steps are needed to create a variable. One is to request a piece of memory, the constructor is invoked to initialize the operation, and the other is to assign a pointer to the block of memory. Those two operations who were in the front after that. The JVM specification is not defined. So there is a situation where the JVM first opens up a piece of memory, then points the pointer to that memory, and finally calls the constructor to initialize it. Let's consider a situation where thread a begins to create an instance of Singletonclass, at which point thread B calls the getinstance () method, first determining whether the instance is null. According to the memory model we mentioned above, A has already pointed the instance to that memory, but has not called the constructor method, so B detects that instance is not NULL, and then returns the instance directly--the problem arises, although instance is not NULL, But it's not finished, like a house has given you the key, but you can't live in it because it's not packed. At this point, if B uses this instance before a instance construct is completed, the program will have an error. So, we thought of the following code:
public class Singletonclass {private static Singletonclass instance = NULL; 
      public static Singletonclass getinstance () {if (instance = null) {Singletonclass SC; 
        Synchronized (singletonclass.class) {sc = instance; if (sc = = null) {synchronized (Singletonclass.class) {if (sc = null) {sc = new S 
            Ingletonclass (); 
        } instance = SC; 
  }} return instance; Private Singletonclass () {}} 
We create a temporary variable in the first sync block, then use the temporary variable to create the object, and at the end, instance the pointer to the memory space of the variable. Writing this code is based on the idea that synchronized will act as a code shield, and that the code inside the sync block is not connected to the external code. Therefore, the operation of the temporary variable SC inside the external synchronization block does not affect the instance, so the outer class is INSTANCE=SC before the instance is detected, and the result instance is still null. However, this idea is completely wrong. The release of the synchronized block guarantees that the operation prior to that-that is, in the sync block-must be completed, but does not guarantee that the operation after the sync block will not be replaced by the compiler optimizations before the end of the synchronization block. Therefore, the compiler can completely instance=sc the sentence into the internal synchronization block to execute. In this way, the procedure is wrong again. 6. The solution said so much, can not be a single example in Java to implement it. Fact After JDK 5, Java used a new memory model. The volatile keyword has a clear semantics--before JDK1.5, volatile is a keyword, but it does not explicitly specify its purpose--the volatile-modified write variable cannot be adjusted to the previous read-write code, the read variable cannot be adjusted to the read-write code after it. So, as long as we simply add instance to the volatile keyword.
public class Singletonclass { 
  Private volatile static singletonclass instance = null; 
  public static Singletonclass getinstance () { 
    if (instance = null) { 
      synchronized (Singletonclass.class) 
        { if (instance = = null) { 
          instance = new Singletonclass () 
        ; 
    }}} return instance; 
  } 
  Private Singletonclass () { 
  } 
}
However, this is just the JDK1.5 Java solution, before that version. In fact, there is another solution that is not affected by the Java version:
public class Singletonclass { 
  private static class Singletonclassinstance { 
    private static final Singletonclass I Nstance = new Singletonclass (); 
  } 
  public static Singletonclass getinstance () {return 
    singletonclassinstance.instance; 
  } 
  Private Singletonclass () { 
  } 
}
In this version of the single example pattern implementation code, we use the Java static inner class. This technique is clearly stated by the JVM, so there is no ambiguity. In this code, because Singletonclass does not have a static property, it is not initialized. Until the getinstance () is invoked, the Singletonclassinstance class is loaded first, and the class has a static Singletonclass instance, so the Singletonclass construction method needs to be called. getinstance () then returns the instance of the inner class to the user. Because this instance is static, it does not construct multiple times. Because Singletonclassinstance is a private static inner class, it is not known to other classes, and static semantics also requires that no multiple instances exist. Also, the JSL specification defines that the construction of a class must be atomic and not concurrent, and therefore does not need to be added to the synchronization block. Similarly, since this construct is concurrent, getinstance () does not need to be synchronized. Now that we have a complete understanding of the single case pattern in the Java language, two solutions are proposed. Personal preference for the second, and Effiective Java also recommended this way.
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.