Java Design Patterns Singleton

The so-called single-mode embodiment, the entire application is simply to ensure that only the present instance of a class. Like the Java Web application, that is, it provides a global variable, use a wide range, such as saving the global data, and so on to achieve global operations.

  • 1.1 The simplest implementation

First of all, be able to think of the simplest implementation is written in the class constructor private so as to ensure that other classes can not instantiate this class, and then provide a static instance of the class and returned to the user. Thus, the user can use the reference to the instance of this class.

public class SingletonClass {

  private static final SingletonClass instance = new SingletonClass();
    
  public static SingletonClass getInstance() {
    return instance;
  }
    
  private SingletonClass() {
    
  }  
}

Example above, if the user requires the use of external SingletonClass instance, the only through getInstance () method, and its constructor is private, thus ensuring that only one object exists.

  • 1.2 Performance Optimization --lazy loaded

The above code is simple, but there is a question: whether or not the class is used, will create an instance object. If this process is very time-consuming to create, for example, you need to connect 10000 database (exaggerated ... :-)), and this class also will not necessarily be used, then the creation process is useless. How to do it?

To solve this problem, we think of the new solution:

public class SingletonClass {

  private static SingletonClass instance = null;
    
  public static SingletonClass getInstance() {
    if(instance == null) {
      instance = new SingletonClass();
    }
    return instance;
  }
    
  private SingletonClass() {
    
  } 
}

Change the code, there are two - first, the instance is initialized to null, until the first time used to create the object by determining whether null. Because creating is not declared at the process, so that the final modifications must be removed.

Let's imagine this process. To use SingletonClass, call getInstance () method. The first time found that instance is null, then create a new object, return out; the second time when re-use, because this instance is static, it is not null, and therefore will not create an object, it directly return.

This process has become lazy loaded, that is, late loading - until time to use it to load.

  • 1.3 Synchronization

The above code is very clear, very simple. But in a single-threaded, this code is no problem, but if multiple threads, trouble came. such as:

A thread you want to use SingletonClass, call getInstance () method. Because it is the first call, A found instance is null, then it begins to create an instance, at this time, the CPU time slice switching occurs, thread B starts executing, it will use SingletonClass, call getInstance () method, the same detection null-- instance is to note that this is to switch after the tests are completed, a, that a did not have time to create an object - so B started. After B created, switch to the A to continue because it has detected over, so A will not detect it again, it will create objects directly. Thus, A and B each thread has a SingletonClass objects - the single cases of failure!

The solution is very simple, it is locked:

public class SingletonClass {

  private static SingletonClass instance = null;
    
  public synchronized static SingletonClass getInstance() {
    if(instance == null) {
      instance = new SingletonClass();
    }
    return instance;
  }
    
  private SingletonClass() {
    
  }   
}
  • 1.4 performance issues

The above code is very simple and very clear, however, the simple things are often less than ideal. This code is no doubt there is a performance problem --synchronized modified sync block but slower than the average piece of code on several times! If there are many times getInstance () call, that performance issues would have to consider it!

Let us analyze, what is the whole method must be locked, or just a one in which the lock is enough? Why should we lock it? Analyze the reasons for that situation is lazy loaded. The reason is that operation of the operation and create objects of detection of null separated. If these two operations can be performed atomically, then a single embodiment has been guaranteed. So, we began 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 getInstance () of the synchronization operation, the synchronization lock and then loaded on the if statement. But such modifications not have any effect: because each call to getInstance () when bound to synchronize, performance problems still exist. If ...... If we determine in advance what is not is null sync to go?

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() {

  }

}

Any question? Analyzing first instance is not null, and if is null, initialization lock; if not null, is directly returned instance. This is double-checked locking design single-mode embodiment. So far, everything is perfect. We use a very clever way to achieve a singleton pattern.

  • 1.5 check from the source

Here we begin to say compiler theory. The so-called compiler, the source code is "translated" into object code - mostly refers to machine code - process. For Java, which is the object code is not native machine code, but a virtual machine code. Compiler theory there is a very important element compiler optimizations. The so-called compiler optimization is, without changing the original semantics by adjusting the sentence order, to make the program run faster. This process becomes reorder.

You know, JVM just a standard is not achieved. JVM and no provisions compiler optimized content, that is to say, free JVM implementation can be optimized compiler.

Let's think about what steps to create a variable need it? Application is a piece of memory, call the constructor method of initialization, the other is to assign a pointer to this memory. These two operations who is who in the previous post it? JVM specification does not specify. Then there is such a situation, JVM is to carve out a memory, then the pointer to this memory, and finally call the constructor to initialize.

Let us consider such a situation: A thread creates an instance of SingletonClass the beginning, then thread B calls the getInstance () method, first determine whether the instance is null. As we said above memory model, A've instance pointing to that memory, but there was no call the constructor method, so B is detected instance is not null, then returned directly to the instance - the question arises, though no instance it is null, but it has not been constructed, just as a house has given you the keys, but you can not live in, because it was not packed yet. In this case, if the instance of B in A completed before construction is to use this instance, the program will error occurred!

So, we think 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 SingletonClass();
            }
          }
          instance = sc;
        }
      }
    }
    return instance;
  }

  private SingletonClass() {

  }
    
}

We created in the first sync block inside a temporary variable, and then use this temporary variable to create an object, and in the end the temporary memory space pointer instance variable. This code is based on the idea to write, i.e., will function as a synchronized shield codes, codes, and outer code sync block does not contact the inside. Thus, the temporary variable sc external sync blocks in which instance does not affect the operation, so in the outer class instance = sc; time instance before the detection, the result instance is still null.

However, this idea is completely wrong! Release synchronized block to ensure that before - that is synchronized block inside - operations must be done, but does not guarantee the operation after the synchronization block can not be due to compiler optimizations and transposed to carry out before the end of the sync block. Therefore, the compiler can put instance = sc; phrase moved inside the internal sync blocks performed. In this way, the program is wrong!

  • 1.6 Solution

Having said that, there is no way to do a single case in Java to achieve it? actually not!

After JDK 5, Java uses a new memory model. The volatile keyword with a clear semantics - before JDK1.5, volatile is a keyword, but not clearly defined its purpose - to be volatile write variables can not be modified and adjusted before reading and writing the code, and can not read variables read and write the code after the adjustment! Therefore, if we simply put instance plus the volatile keyword on it.

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 only after JDK1.5 Java solution that previous versions of it? In fact, there is another kind of solution will not be affected Java versions:

public class SingletonClass {
    
  private static class SingletonClassInstance {
    private static final SingletonClass instance = new SingletonClass();
  }

  public static SingletonClass getInstance() {
    return SingletonClassInstance.instance;
  }

  private SingletonClass() {

  }
    
}

Singleton pattern implementation code in this version, we use a Java static inner classes. This technique is clearly stated in the JVM, so any ambiguity does not exist. In this code, because there is no static SingletonClass properties, and therefore are not initialized. Until when calling getInstance (), it will first load SingletonClassInstance class that has SingletonClass instance of a static, so you need to call the constructor SingletonClass, and getInstance () will return this internal class instance to the user. Since this instance is static, so many times and will not be constructed.

Since SingletonClassInstance private static inner class, so it will not be known to other classes, likewise, there will be no static semantics requires multiple instances. And, JSL specification defines, configuration class must be atomic, uncomplicated, and therefore does not need to add sync blocks. Also, since this structure is concurrent, so getInstance () does not need to add synchronized.

At this point, we have a complete understanding of the Singleton pattern when the Java language, we propose two solutions. Personally I prefer the second, and Effiective Java also recommended this approach.

This article comes from "bean Space" blog, be sure to keep this source http://devbean.blog.51cto.com/448512/203501

Guess you like

Origin www.cnblogs.com/jlutiger/p/11088961.html