Singleton design pattern introduction

The singleton design pattern of a class takes certain measures to ensure that there is only one instance of an object of a class in the entire software system, and that the class provides only one method (static method) to get the instance of the object.

Hibernate’s SessionFactory, for example, acts as a proxy for the data store source and is responsible for creating Session objects. SessionFactory is not lightweight. In general, a project only needs one SessionFactory, which is where the singleton pattern is used.

1.1 There are eight singleton design patterns

There are eight types of singletons: 1. Hungry (static constant) 2. Hungry (static code block) 3. Lazy (thread-unsafe) 4. Lazy (thread-safe, synchronized method) 5. Lazy (thread-safe, synchronized code blocks) 6. Double checking 7. Static inner classes 8. The enumeration

2 Hungry (static constant)

Examples of the application of Hungry (static constant) are as follows:

  1. Constructor privatization (prevent new)
  2. Class creates objects internally
  3. Expose a static public method to the outside. getInstance

Code implementation:

Public static void main(String[] args) {public static void main(String[] args) {public static void main(String[] args) 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 {//1. New private Singleton() {} //2; Private final static Singleton instance = new Singleton(); private final static Singleton instance = new Singleton(); Public static Singleton getInstance() {return instance;} public static Singleton getInstance() {return instance; }}

2.1 Advantages and disadvantages:

Advantages:

  1. This is a simple way to instantiate the class when it is loaded. Thread synchronization issues are avoided.

Disadvantages:

  1. The class is instantiated when the class is loaded. No Lazy Loading is achieved. If the instance is never used from the beginning to the end, memory is wasted.
  2. This method is based on the classLoder mechanism to avoid the synchronization problem of multiple threads, but the instance is instantiated when the class is loaded. In singleton mode, most of the method is called getInstance, but there are many reasons why the class is loaded. Therefore, there is no other way (or other static method) to load the class, and initializing instance will not perform the lazy loading.
  3. Conclusion: This singleton pattern is useful and can be a memory waste.

3. Hungry (static code block)

Public class SingletonTest02 {public static void main(String[] args) {public static void main(String[] args) Singleton2.getInstance(); Singleton2 instance2 = Singleton2.getInstance(); System.out.println(instance == instance2); // true System.out.println("instance.hashCode=" + instance.hashCode()); System.out.println("instance2.hashCode=" + instance2.hashCode()); }} // class Singleton2 {//1. New private Singleton2() {} //2; Private static Singleton2 instance; private static Singleton2 instance; Static {instance = new Singleton2(); static {instance = new Singleton2(); } public static Singleton2 getInstance() {return instance;} public static Singleton2 getInstance() {return instance; }}

Advantages and disadvantages:

  1. This method is similar to the above method, except that the class instantiation process is placed in the static code block, and the code in the static code block is executed when the class is loaded to initialize the instance of the class. The pros and cons are the same as above.
  2. Conclusion: This singleton pattern works, but can be a memory waste.

4. Lazy (thread unsafe)

Public class singletonTest03 {public static void main(String[] args) {System.out.println(" String 1, thread-safe ~"); Singleton3 instance = Singleton3.getInstance(); Singleton3 instance2 = Singleton3.getInstance(); System.out.println(instance == instance2); // true System.out.println("instance.hashCode=" + instance.hashCode()); System.out.println("instance2.hashCode=" + instance2.hashCode()); } } class Singleton3 { private static Singleton3 instance; Private Singleton3() {} // Instance is created when a static public method is used. Public static Singleton3 getInstance() {if (instance == null) {instance = new Singleton3(); } return instance; }}

4.1 Advantages and disadvantages:

  1. Loading is performed, but only on a single thread.
  2. If one thread enters the if (singleton == null) block and another thread passes the block before it can proceed, multiple instances will be generated. So you can’t use this in a multithreaded environment
  3. Bottom line: Do not use this approach in real development.

5 Lazy (thread-safe, synchronous methods)

Public class singletonTest04 {public static void main(String[] args) {System.out.println(" thread-safe ~"); Singleton4 instance = Singleton4.getInstance(); Singleton4 instance2 = Singleton4.getInstance(); System.out.println(instance == instance2); // true System.out.println("instance.hashCode=" + instance.hashCode()); System.out.println("instance2.hashCode=" + instance2.hashCode()); }} // class Singleton4 {private static Singleton4 instance; Private singleLon4 () {} // Provides a static public method with synchronized processing code to solve the thread-safety problem. Public static Singleton4 getInstance() {if (instance == null) {instance = new Singleton4(); public static Singleton4 getInstance() {if (instance == null) {instance = new Singleton4(); } return instance; }}

5.1 Advantages and disadvantages:

  1. Solved thread safety issues
  2. Too inefficient, every thread that wants to get an instance of the class executes the getInstance() method synchronously. In fact, this method only executes the instantiation code once. If you want to get an instance of the class, you simply return it. The method is too inefficient to synchronize.
  3. Conclusion: It is not recommended to use this method in practical development.

6 Lazy (thread unsafe, synchronized blocks of code)

Public class singletonTest05 {public static void main(String[] args) {System.out.println(" Thread-safe ~"); Singleton5 instance = Singleton5.getInstance(); Singleton5 instance2 = Singleton5.getInstance(); System.out.println(instance == instance2); // true System.out.println("instance.hashCode=" + instance.hashCode()); System.out.println("instance2.hashCode=" + instance2.hashCode()); }} // class Singleton5 {private static Singleton5 instance; Private Singleton5() {} // Provides a static public method, adding synchronized processing code, to solve the thread-safety problem. Public static Singleton5 getInstance() {if (instance == null) {// Synchronized (singleton5.class) {public static Singleton5 getInstance() {if (instance == null) { instance = new Singleton5(); } } return instance; }}

Conclusion: Thread is not safe and is not recommended

7 Double check

Public class singletonTest06 {public static void main(String[] args) {System.out.println(" double check "); Singleton6 instance = Singleton6.getInstance(); Singleton6 instance2 = Singleton6.getInstance(); System.out.println(instance == instance2); // true System.out.println("instance.hashCode=" + instance.hashCode()); System.out.println("instance2.hashCode=" + instance2.hashCode()); }} // Class singleLon6 {/** * volatile, instance is visible between threads. * private static volatile Singleton6 instance; * private static volatile Singleton6 instance; * private static volatile Singleton6 instance; Private Singleton6() {} // Provides a static public method that adds double-checked code to address thread-safety issues and lazy loading issues. While maintaining efficiency, Public static Singleton6 getInstance() {if (instance == null) {synchronized (singleton6.class) {if (instance == null) { instance = new Singleton6(); } } } return instance; }}

7.1 Advantages and disadvantages:

  1. The double-check concept is commonly used in multithreaded development, and as shown in the code, we perform an if (singleton == null) Check twice to ensure thread-safety.
  2. In this way, the instantiation code is executed only once, and on subsequent visits, if (Singleton == NULL) is determined to return the instantiation object directly, avoiding repeated method synchronization.
  3. Thread safety; Lazy loading; High efficiency.
  4. Conclusion: It is recommended to use this singleton design pattern in practice.

Static inner classes

Public class singletonTest07 {public static void main(String[] args) {System.out.println(" Use static inner classes to complete singletonTest07 "); Singleton7 instance = Singleton7.getInstance(); Singleton7 instance2 = Singleton7.getInstance(); System.out.println(instance == instance2); // true System.out.println("instance.hashCode=" + instance.hashCode()); System.out.println("instance2.hashCode=" + instance2.hashCode()); }} /** * Static inner class is complete, and it is recommended to use the * static inner class mechanism: * 1. When the outer class is loaded, the static inner class is not loaded. * 2, When an external class calls a static variable inside a static inner class, it causes the static inner class to be loaded. * 3, When a class is state, it is thread-safe. A class load is not accessible by other threads. * So the singleton pattern is implemented through the mechanism of static inner classes. */ class Singleton7 {// private Singleton7() {} // Write a static inner class that has a static property Singleton private static class SingletonInstance { private static final Singleton7 INSTANCE = new Singleton7(); } // provide a static public method, Direct return SingletonInstance. INSTANCE public static Singleton7 getInstance () {return SingletonInstance. INSTANCE; }}

8.1 Advantages and disadvantages:

  1. This approach uses the class-loading mechanism to ensure that the instance is initialized with only one thread.
  2. The static inner-class approach does not instantiate the Singleton class immediately when it is loaded. Instead, the SingletonInstance class is loaded and instantiated by calling the getInstance method when instantiation is needed.
  3. Static properties of a class are initialized only the first time the class is loaded, so here the JVM helps keep threads safe from other threads while the class is initialized.
  4. Advantages: avoid thread insecurity, use static inner class characteristics to achieve lazy loading, high efficiency.
  5. Conclusion: Recommended.

9 the enumeration

public class SingletonTest08 { public static void main(String[] args) { Singleton8 instance = Singleton8.INSTANCE; Singleton8 instance2 = Singleton8.INSTANCE; System.out.println(instance == instance2); System.out.println(instance.hashCode()); System.out.println(instance2.hashCode()); instance.sayOK(); }} // Enum Singleton8 {// attribute INSTANCE; public void sayOK() { System.out.println("ok~"); }}

9.1 Advantages and disadvantages:

  1. This implements the singleton pattern with the help of enumerations added in JDK1.5. Not only does this avoid the problem of multithreading synchronization, but it also prevents deserialization from recreating new objects.
  2. This approach is advocated by Effective Java author Josh Bloch
  3. Conclusion: Recommended.

Singleton pattern in JDK application source analysis

  1. In our JDK, java.lang.Runtime is the classic singleton pattern.
  2. Code analysis +Debug source code + code description

Singleton pattern notes and details

  1. Singleton pattern ensures that only one object of the class exists in system memory, saving system resources. For some objects that need to be created and destroyed frequently, using singleton pattern can improve system performance
  2. When you want to instantiate a singleton class, you must remember to use the corresponding method to get the object, not new
  3. Scenarios used by the singleton pattern: objects that need to be created and destroyed frequently, objects that take too much time or resources to create (i.e., heavyweight objects), objects that are frequently used, objects of utility class, objects that frequently access databases or files (e.g., data sources, session factories, etc.)