Design Patterns - Single Case Design Patterns

1. Hungry Han Style (Static Constant)

The steps are as follows:

  1. Privatization of constructors (prevent new)
  2. Create objects inside classes
  3. Expose a static public method to the outside world. getInstance
  4. code implementation
public class SingletonTest01 {

	public static void main(String[] args) {
		//test
		Singleton instance = Singleton.getInstance();
		Singleton instance2 = Singleton.getInstance();
		System.out.println(instance == instance2); // true
		System.out.println("instance.hashCode=" + instance.hashCode());
		System.out.println("instance2.hashCode=" + instance2.hashCode());
	}

}

//Hungry Han Style (Static Variable)

class Singleton {
	
	//1. Constructor Privatization, External Energy new
	private Singleton() {
		
	}
	
	//2. Create object instances within this class
	private final static Singleton instance = new Singleton();
	
	//3. Provide a public static method to return instance objects
	public static Singleton getInstance() {
		return instance;
	}
	
}

Advantages and disadvantages:

  1. Advantage: Instantiation is done when the class is loaded. Thread synchronization issues are avoided.
  2. Disadvantages: Lazy Loading is not achieved. If you never use this instance from start to finish, it will cause a waste of memory
  3. This approach avoids multi-threaded synchronization problems based on the classloder mechanism, but instances are instantiated when classes are loaded. Most of the calls to the getInstance method are in the singleton mode, but there are many reasons for class loading. Therefore, it is not certain that there are other ways (or other static methods) that cause the class to load, and initializing instances will not have the effect of lazy loading.
  4. Conclusion: This single-case mode is available and may cause memory waste

2. Hungry Han Style (Static Code Block)

public class SingletonTest02 {

	public static void main(String[] args) {
		//test
		Singleton instance = Singleton.getInstance();
		Singleton instance2 = Singleton.getInstance();
		System.out.println(instance == instance2); // true
		System.out.println("instance.hashCode=" + instance.hashCode());
		System.out.println("instance2.hashCode=" + instance2.hashCode());
	}

}

//Hungry Han Style (Static Variable)

class Singleton {
	
	//1. Constructor Privatization, External Energy new
	private Singleton() {
		
	}
	
	//2. Create object instances within this class
	private  static Singleton instance;
	
	static { // Create a singleton object in a static block of code
		instance = new Singleton();
	}
	
	//3. Provide a public static method to return instance objects
	public static Singleton getInstance() {
		return instance;
	}
	
}
  1. This is similar to the above except that the process of instantiating a class is placed in a static block of code, and when the class is loaded, the code in the static block of code is executed to initialize an instance of the class. The advantages and disadvantages are the same as above.
  2. Conclusion: This single-case mode is available, but may cause memory waste

3. Lazy (thread insecure)

public class SingletonTest03 {

	public static void main(String[] args) {
		System.out.println("Lazy 1, thread insecurity~");
		Singleton instance = Singleton.getInstance();
		Singleton instance2 = Singleton.getInstance();
		System.out.println(instance == instance2); // true
		System.out.println("instance.hashCode=" + instance.hashCode());
		System.out.println("instance2.hashCode=" + instance2.hashCode());
	}

}

class Singleton {
	private static Singleton instance;
	
	private Singleton() {}
	
	//Provides a static public method that is used to create an instance
	//Lazy Man Style
	public static Singleton getInstance() {
		if(instance == null) {
			instance = new Singleton();
		}
		return instance;
	}
}

Advantages and disadvantages:

  1. Lazy Loading works, but can only be used under a single thread.
  2. If, under multithreading, one thread enters the if (singleton == null) judgment block and has not yet had time to execute down, and another thread passes the judgment, multiple instances will be generated. This is not possible in a multi-threaded environment
  3. Conclusion: Do not use this method in actual development.

4. Lazy (thread-safe, synchronization method)

public class SingletonTest04 {

	public static void main(String[] args) {
		System.out.println("Lazy 2, thread safe~");
		Singleton instance = Singleton.getInstance();
		Singleton instance2 = Singleton.getInstance();
		System.out.println(instance == instance2); // true
		System.out.println("instance.hashCode=" + instance.hashCode());
		System.out.println("instance2.hashCode=" + instance2.hashCode());
	}

}

// Lazy (thread-safe, synchronization method)
class Singleton {
	private static Singleton instance;
	
	private Singleton() {}
	
	//Provides a static, public way to incorporate synchronized code to address thread security issues
	//Lazy Man Style
	public static synchronized Singleton getInstance() {
		if(instance == null) {
			instance = new Singleton();
		}
		return instance;
	}
}

Advantages and disadvantages:

  1. Resolved thread insecurity
  2. Too inefficient, each thread synchronizes the execution of the getInstance() method when it wants to get an instance of the class. In fact, it's enough to execute the instantiation code only once. To get such an instance later, simply return it. Method synchronization is too inefficient
  3. Conclusion: This method is not recommended in actual development.

5. Lazy (Thread Safe, Synchronize Code Blocks)


Advantages and disadvantages:

  1. This is intended to improve the fourth implementation because the previous synchronization method was too inefficient and resulted in instantiated blocks of code being synchronized
  2. However, this synchronization does not work as thread synchronization. Consistent with the third implementation, if a thread enters an if (singleton == null) judgment block and has not yet had time to execute down, and another thread passes the judgment, multiple instances will be generated
  3. Conclusion: This method cannot be used in actual development.

6. Double Check

public class SingletonTest06 {

	public static void main(String[] args) {
		System.out.println("duplication check");
		Singleton instance = Singleton.getInstance();
		Singleton instance2 = Singleton.getInstance();
		System.out.println(instance == instance2); // true
		System.out.println("instance.hashCode=" + instance.hashCode());
		System.out.println("instance2.hashCode=" + instance2.hashCode());
		
	}

}

// Lazy (thread-safe, synchronization method)
class Singleton {
	private static volatile Singleton instance;
	
	private Singleton() {}
	
	//Provides a static, public method that adds double-checking code to solve thread security and lazy loading problems
	//It also ensures efficiency and is recommended for use
	
	public static synchronized Singleton getInstance() {
		if(instance == null) {
			synchronized (Singleton.class) {
				if(instance == null) {
					instance = new Singleton();
				}
			}
			
		}
		return instance;
	}
}

Advantages and disadvantages:

  1. The Double-Check concept is commonly used in multithreaded development, and as shown in the code, we performed two if (singleton == null) checks to ensure thread safety.
  2. This way, the instantiation code is executed only once, and when accessed again later, if (singleton == null), the instantiation object is return ed directly, and method synchronization is avoided.
  3. Thread security; Delayed loading; Higher efficiency
  4. Conclusion: This single-case design pattern is recommended for practical development.

7. Static Internal Class

public class SingletonTest07 {

	public static void main(String[] args) {
		System.out.println("Complete singleton mode using static internal classes");
		Singleton instance = Singleton.getInstance();
		Singleton instance2 = Singleton.getInstance();
		System.out.println(instance == instance2); // true
		System.out.println("instance.hashCode=" + instance.hashCode());
		System.out.println("instance2.hashCode=" + instance2.hashCode());
		
	}

}

// Static internal class complete, recommended
class Singleton {
	private static volatile Singleton instance;
	
	//Constructor Privatization
	private Singleton() {}
	
	//Write a static internal class with a static property Singleton
	private static class SingletonInstance {
		private static final Singleton INSTANCE = new Singleton(); 
	}
	
	//Provides a static public method that returns SingletonInstance directly. INSTANCE
	
	public static synchronized Singleton getInstance() {
		
		return SingletonInstance.INSTANCE;
	}
}

Advantages and disadvantages:

  1. This approach uses a class loading mechanism to ensure that there is only one thread initializing the instance.
  2. Static internal class methods do not instantiate when the Singleton class is loaded, but when instantiation is required, call the getInstance method to load the SingletonInstance class to complete the Singleton instantiation.
  3. The static properties of a class are only initialized when it is first loaded, so here, the JVM helps us keep threads safe, and no other threads can enter when the class is initialized.
  4. Advantages: Avoid thread insecurity, use static internal class characteristics to achieve delayed loading, high efficiency
  5. Conclusion: Recommended use

8) Enumeration

public class SingletonTest08 {
	public static void main(String[] args) {
		Singleton instance = Singleton.INSTANCE;
		Singleton instance2 = Singleton.INSTANCE;
		System.out.println(instance == instance2);
		
		System.out.println(instance.hashCode());
		System.out.println(instance2.hashCode());
		
		instance.sayOK();
	}
}

//Enumeration enables singletons, recommended
enum Singleton {
	INSTANCE; //attribute
	public void sayOK() {
		System.out.println("ok~");
	}
}
  1. With JDK1. Enumeration added in 5 to implement singleton mode. Not only does it avoid the problem of multithreaded synchronization, it also prevents deserialization from re-creating new objects.
  2. This is the way that Effective Java author Josh Bloch advocates
  3. Conclusion: Recommended use

Keywords: Design Pattern

Added by Jose Arce on Mon, 03 Jan 2022 05:17:33 +0200