To implement the singleton pattern, the following conditions must be met:

  1. Singleton classes must be final (inheritance is not allowed)
  2. Private Constructor (private)
  3. Create a class method to get instance objects (static)
// Final does not allow inheritance
pubilc final class Singleton{
  // Private constructor, does not allow external new
	private Singleton(a){}
	
  // Get the class method of the instance object
	public static Singleton getInstance(a){
 		
    returninstance; }}Copy the code

Judging the merits and disadvantages of each implementation method:

  • Thread safety (guaranteed singleton)
  • High performance (allows multiple threads to fetch instance objects simultaneously)
  • Lazy loading (not instantiated until needed)

One, hungry

Set a class variable (using the static modifier) that returns an object directly in the class using the new method. This has the advantage of ensuring that the instance instance is created during class loading (class initialization). Because, as class variables, they can be assigned the correct value in the class initialization execution () method, which is generated at compile time and is already contained in the class file, the JVM guarantees synchronization semantics for the () method in a multithreaded environment, containing all assignment actions for class variables and static block execution code.

Type, but a starving man but simply to ensure that the multithreading under the only instance, and is in a class initialization phase produced a class object, rather than the need to use the recycled into objects, that is not a lazy loading, the downside is that if the members in this class are heavier resources, will be to take up more memory resources.

private static Singleton instance = new Singleton();
Copy the code

Two, slacker style

You want to do lazy loading, lazy loading, which means you need to initialize the instance when it’s needed, which means you don’t initialize it during class loading. Instance can be set to null and then checked in the getInstance method to see if instance has been instantiated. If not, an object is returned.

private static Singleton instance = null;

public static Singleton getInstance(a){
  
  if(null == instance){
    
    return new Singleton();
  }
  
  return instance;
}
Copy the code

This is not guaranteed in a multithreaded environment because there is no synchronization in the getInstance method, which can result in instance being instantiated multiple times.

In fact, this is not to meet the basic requirements of the singleton pattern, wrong writing.

Lazy + synchronous method

In this case, add the synchronized keyword to the getInstance method for synchronization control

public static synchronized Singleton getInstance(a){
  
  if(null == instance){
    return new Singleton();
  }
  
  return instance;
}
Copy the code

However, doing so can result in poor performance when subsequent threads getInstance, because only one thread is allowed to access the getInstance method at a time. (There is no need to compromise performance in order to ensure thread-safety on the first build.)

Fourth, Double – Check

if(null == instance){
  
  synchronized(Singleton.class){
    
    if(null == instance){
      return newSingleton(); }}}Copy the code

This allows lazy loading and uniqueness of instance instances, while allowing multiple thread colleagues to access the getInstance method. In a multithreaded environment, however, this logic can cause a null-pointer exception (and each judgment is made first, which is an additional judgment, but this should be ignored), because if there are other resources that need to be initialized in the Singleton constructor, Due to JVM runtime instructions reordering and happens-before rules, there is no prior or subsequent constraint on the order of other resources and instance instances. Instance instances have been instantiated, but the other resources have not been instantiated, and another thread accesses the instance and determines that instance is not null. A null pointer exception is reported when using the instance variable resource of a class directly.

Five, the Volatile + Double – Check

public volatile static Singleton instance = null;  
Copy the code

The JVM instruction reorder is directly disabled by adding the volatile keyword.

Six, Holder,

Hold instance objects by creating a static inner class within the class.

private static class Holder{
  private static Singleton instance = new Singleton();
}

public static Singleton getInstance(a){
  return Holder.instance;
}
Copy the code

Placing new Singleton() in a static inner class, the () method executed during class load initialization when the Holder class is first used, guarantees synchronization semantics (memory visibility, sequential and atomicity of JVM instructions). This approach is one of the best singleton designs.

Seven, Enum

Enumerated types are not allowed to be inherited, are also thread-safe and can only be instantiated once.

public enum Singleton{
  
  INSTANCE;
  Singleton(){}
  
  public static void method(a){}public static Singleton getInstance(a){
    
    returnINSTANCE; }}Copy the code

The code above does not allow lazy loading and can be improved in a manner similar to Holder:

public class Singleton{
  
  private Singleton(a){}
  
  private enum EnumHolder{
    
    INSTANCE;
    private Singleton instance;
    
    EnumHolder(){
      this.instance = new Singleton();
    }
    
    private Singleton getSingleton(a){
      returninstance; }}public static Singleton getInstance(a){
    
    returnEnumHolder.INSTANCE.getSingleton(); }}Copy the code

This article is from “Java high concurrent programming in detail”, recorded for everyone to learn ~