Daily learning - Java design pattern (Day8) -- singleton pattern

Posted by chomedey on Tue, 22 Feb 2022 07:18:53 +0100

We must put forward such tasks for ourselves: first, learning, second, learning, and third, learning.
There is never a shortcut to learning. You can reach the peak step by step.

1, Introduction to single example design mode

The so-called class singleton design pattern is to take certain methods to ensure that there can only be one object instance for a class in the whole software system, and the class only provides a method to obtain its object instance (static method).

For example, Hibernate's SessionFactory acts as a proxy for the data storage source and is responsible for creating the Session object. SessionFactory is not lightweight. Generally, only one SessionFactory is needed for a project. In this case, the singleton mode will be used.

2, Eight ways of single case design mode

  1. Hungry Han formula (static constant)
  2. Hungry Chinese style (static code block)
  3. Lazy (thread unsafe)
  4. Lazy (thread safety, synchronization method)
  5. Lazy (thread safe, synchronous code block)
  6. duplication check
  7. Static inner class
  8. enumeration

3, Code examples of eight methods

1. Hungry Han formula (static constant)

  1. Constructor Privatization (prevent new)
  2. Declare static member variables and create objects
  3. Expose a static public method. getInstance
  4. code implementation
class Singleton {
    private static final Singleton instance = new Singleton();

    private Singleton() {
    }

    public static Singleton getInstance() {
        return instance;
    }
}

Description of advantages and disadvantages:

  1. Advantages: this method is relatively simple, that is, the instantiation is completed when the class is loaded. Thread synchronization problems are avoided.
  2. Disadvantages: the instantiation is completed when the class is loaded, which does not achieve the effect of Lazy Loading. If you have never used this instance from beginning to end, it will cause a waste of memory
  3. This method is based on the classloder mechanism and avoids the problem of multi-threaded synchronization. However, instance is instantiated during class loading. In the singleton mode, most of them call the getInstance method, but there are many reasons for class loading. Therefore, it is uncertain that other methods (or other static methods) lead to class loading, At this time, initializing instance does not achieve the effect of lazy loading
  4. Conclusion: This singleton mode is available, which may cause a waste of memory

Some people here may not understand it very well. Some beginners may have these questions:

1. I can use static variables directly to make it a singleton. Why is it so complicated?

The following is an example of an inverse:

  • static final is used to modify variables to ensure unity.
  • Privatize the constructor to prevent the outside world from directly creating objects through new. Then, when we want to use this object, we can directly use singleton Single to get the object.
class Singleton {
    public static final Singleton single = new Singleton();

    private Singleton() {
        System.out.println("instantiation  Singleton");
    }
}

Test:

public class Test1 {
    public static void main(String[] args) {
        System.out.println(Singleton.single);
        System.out.println(Singleton.single);
    }
}


Serious problems:

A singleton not only means that the object remains single in the project, but also ensures that it will not be modified. Although the above example uses final to modify the member variable, it uses public to modify the member variable. It means that the access object can be accessed through the class name Member variables.

If final is used to modify the reference variable, although it cannot change the object (reference address), it can change other properties of the object. Violation of single case regulations.

Supplementary knowledge

final finishing features:

  1. Modified class: modified class, indicating that this class cannot be inherited
  2. As like as two peas, the method of modification is to show that the method can not be covered by subclasses, that is, subclasses can not be exactly the same as the parent class.
  3. Modified variable: the final member variable represents a constant and can only be assigned once. The value will not change after assignment. The value here does not change. There are two data types
    Modify basic data type: indicates that the value of this basic data type cannot be changed after initialization
    Modify reference type: after its initialization, it can no longer point to other objects, but the content of the object pointed to by the reference can be changed

static modifier member variable attribute:

  1. Variables are instantiated when the class is loaded. (accessing methods, variables, or new objects in the class will load the class)
  2. The variable modified by static is also called class variable. It does not belong to the variable of the object, so we can directly pass the class name Member variable access, but if private is set, the outside world cannot access it in this form.

2. Hungry Chinese style (static code block)

class Singleton {

    //1. The constructor is privatized and the external energy is new
    private Singleton() {
        System.out.println("instantiation ");
    }

    //2. Create object instances within this class
    private static Singleton instance;

    static { // In a static code block, create a singleton object
        instance = new Singleton();
    }

    //3. Provide a public static method to return the instance object
    public static Singleton getInstance() {
        return instance;
    }

}

Description of advantages and disadvantages:

  1. This method is actually similar to the above method, except that the class instantiation process is placed in the static code block. When the class is loaded, the code in the static code block is executed to initialize the class instance. The advantages and disadvantages are the same as those above.
  2. Conclusion: This singleton mode is available, but it may cause a waste of memory

3. Lazy (thread unsafe)

class Singleton {
    private static Singleton instance;

    private Singleton() {
    }

    //Provide a static public method. Create instance only when this method is used
    //Lazy style
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

Description of advantages and disadvantages:

  1. It has the effect of Lazy Loading, but it can only be used under single thread.
  2. If a thread enters the if (singleton == null) judgment statement block and has not had time to execute, and another thread also passes the judgment statement, multiple instances will be generated. Therefore, this method cannot be used in a multithreaded environment
  3. Conclusion: do not use this method in actual development

4. Lazy (thread safety, synchronization method)

class Singleton {
	private static Singleton instance;
	
	private Singleton() {}
	
	//Provide a static public method, add synchronous processing code, and solve thread safety problems
	//Lazy style
	public static synchronized Singleton getInstance() {
		if(instance == null) {
			instance = new Singleton();
		}
		return instance;
	}
}

Description of advantages and disadvantages:

  1. The thread unsafe problem is solved
  2. The efficiency is too low. When each thread wants to obtain an instance of a class, it needs to synchronize the getInstance() method. In fact, this method only executes the instantiation code once. If you want to obtain this kind of instance later, just return it directly. Method is too inefficient to synchronize
  3. Conclusion: this method is not recommended in practical development

5. Lazy (thread safe, synchronous code block)

// Lazy (thread safety, synchronization method)
class Singleton {
    private static volatile Singleton instance;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
            	instance = new Singleton();
            }
        }
        return instance;
    }
}

Description of advantages and disadvantages:

  1. This method is intended to improve the fourth implementation method. Because the efficiency of the previous synchronization method is too low, the instantiated code block is generated synchronously
  2. But this kind of synchronization can not play the role of thread synchronization. Consistent with the situation encountered in the third implementation method, if a thread enters the if (singleton == null) judgment statement block and has not yet had time to execute, another thread also passes the judgment statement. Although there is a lock after the if judgment, it has entered the if judgment. The meaning of locking is to let the thread execute one by one, and the thread has come in, This lock will not work at all, and multiple instances will be generated
  3. Conclusion: this method cannot be used in practical development

6. Double check

class Singleton {
    private static volatile Singleton instance;

    private Singleton() {
    }

    //Provide a static public method and add double check code to solve the problem of thread safety and lazy loading
    //At the same time, it ensures the efficiency and is recommended to use
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

Description of advantages and disadvantages:

  1. The concept of double check is often used in multithreading development. As shown in the code, we have conducted two if (singleton == null) checks to ensure thread safety.
  2. In this way, the instantiated code is executed only once. When accessing again later, judge if (singleton == null) and return the instantiated object directly, which also avoids repeated method synchronization
  3. Thread safety; Delayed loading; High efficiency
  4. Conclusion: this single case design mode is recommended in practical development

7. Static inner class

// The static internal class is completed, which is recommended
class Singleton {

    //Constructor privatization
    private Singleton() {
    }

    //Write a static inner class with a static attribute Singleton
    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }

    //Provide a static public method and directly return singletoninstance INSTANCE

    public static synchronized Singleton getInstance() {

        return SingletonInstance.INSTANCE;
    }
}

Description of advantages and disadvantages:

  1. This method adopts the mechanism of class loading to ensure that there is only one thread when initializing the instance.
  2. The static internal class method does not instantiate the Singleton class immediately when it is loaded. Instead, when instantiation is needed, call the getInstance method to load the Singleton class, so as to complete the instantiation of Singleton.
  3. The static properties of the class will only be initialized when the class is loaded for the first time, so here, the JVM helps us ensure the safety of threads. When the class is initialized, other threads cannot enter.
  4. Advantages: thread insecurity is avoided, delayed loading is realized by using the characteristics of static internal classes, and the efficiency is high
  5. Conclusion: recommended

8. Enumeration

public class SingletonTest02 {
    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();
    }
}

//Using enumeration, you can realize singleton, which is recommended
enum Singleton {
    INSTANCE; //attribute

    public void sayOK() {
        System.out.println("ok~");
    }
}

Description of advantages and disadvantages:

  1. This is done with the help of jdk1 5 to implement the singleton mode. It can not only avoid the problem of multi-threaded synchronization, but also prevent deserialization and re creation of new objects.
  2. This approach is advocated by Josh Bloch, author of Effective Java
  3. Conclusion: it is recommended to use

Some people may not understand why enumerating classes can be singleton?
In fact, enumeration classes can be decompiled through jad to see the real running code behind enumeration classes.

This is a usage I wrote about jad decompilation: https://blog.csdn.net/weixin_43888891/article/details/122977886?spm=1001.2014.3001.5501

By decompiling the Singleton enumeration class, we can see that the enumeration class is also an ordinary class when running, but the syntax of enumeration is relatively simplified, but the bottom layer remains unchanged.

The following code is decompiled from the Singleton enumeration class. You can see that the attributes in the enumeration class are actually static final modified attributes when running, and are instantiated through static code blocks. To put it bluntly, it is a starving Chinese style (static code block).

4, Source code analysis of singleton mode in JDK application

  1. In our JDK, Java Lang. runtime is the classic singleton mode (hungry Chinese style)
  2. Code analysis + Debug source code + code description

5, Notes and details of singleton mode

  1. The singleton mode ensures that there is only one object in the system memory, which saves system resources. For some objects that need to be created and destroyed frequently, the singleton mode can improve the system performance
  2. When you want to instantiate a singleton class, you must remember to use the corresponding method to get the object instead of new
  3. Scenarios for using singleton mode: objects that need to be created and destroyed frequently, objects that take too much time or resources to create objects (i.e. heavyweight objects), but are often used, tool objects, and objects that frequently access databases or files (such as data sources, session factories, etc.)

Topics: Java Design Pattern Back-end Singleton pattern