define

The singleton pattern is a common design pattern. It aims to ensure that only one instance of a class can be instantiated and provided to the entire system, avoiding frequent object creation and saving memory.

The singleton pattern can be used in many scenarios,

For example, the recycle bin of the operating system of our computer is a good singleton mode application. Files, videos and music on the computer will enter the recycle bin after being deleted. The printer in the computer is also designed by singleton mode. There can be multiple printing tasks in a system, but only one task is working. Counters for Web pages are also implemented in a singleton pattern, eliminating the need to log every refresh to the database.

Reviewing these application scenarios gives us a clearer idea of the core idea of the singleton pattern, which we will implement in code.

Before writing the singleton code, let’s take a quick look at two things: the loading order of classes and the static keyword.

Class loading order

The classLoader mechanism generally follows the following loading order

If the class has not been loaded:

  • The parent class’s static code blocks and variables are initialized first, and the order in which they are executed depends on the order in which the code appears.
  • Performs subclass static code block and static variable initialization.
  • Performs instance variable initialization of the parent class
  • Execute the constructor of the parent class
  • Performs instance variable initialization of the subclass
  • Executes the constructor of the subclass

Also, the process of loading a class is private to the thread and cannot be accessed by other threads.

If the class is already loaded:

Static code blocks and static variables are not executed repeatedly, and when class objects are created, only instance-specific variable initializers and constructors are performed.

The static keyword

If a member variable or method in a class is decorated with the static keyword, that member variable or method is independent of any object in that class. It does not depend on the specific instance, all instances of the Shared by class, as long as the class is loaded, the member variables or methods can be used the name of the class to visit, its role is to describe in one sentence, don’t have to create an object can invoke methods or variables, it’s for the singleton pattern code to realize tailor-made.

Here are a few implementations of the singleton pattern. The key methods are static, and to prevent the singleton class from being frequently created objects, we can use private constructors to ensure that the singleton class cannot be instantiated externally.

Lazy and hungry

In programming, singleton mode is generally divided into two types, namely hungry and lazy.

Hungry: Initialization is done when the class is loaded, so class loading is slow, but object retrieval is fast.

Lazy: does not initialize a class when it is loaded, but only when it is first used.

Code implementation

1. Hungry (available)

public class Singleton {

    private final static Singleton INSTANCE = new Singleton();
    
    private Singleton(){}

    public static Singleton getInstance() {returnINSTANCE; }}Copy the code

This is the most common way to write it, and it is instantiated at class load time, avoiding multithreaded synchronization issues. Of course, there are disadvantages, because the class is instantiated when loaded, so it is not lazily loaded. If the instance is not used, memory is wasted.

2. Plain lazy (thread unsafe, unusable)

public class Singleton {

    private static Singleton instance = null;

    private Singleton() {
    }

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

This is the easiest way to write lazy, and only instantiates the method the first time it is accessed, resulting in lazy loading. However, there is a fatal problem with this method, which is the security problem of multithreading. If the object is not instantiated and two threads access it at the same time, multiple instantiations may occur, so this notation is not acceptable.

3, lazy style of synchronous method (available)

public class Singleton {

    private static Singleton instance = null;

    private Singleton() {
    }

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

This method locks getInstance() and ensures that only one thread can access the instance at a time. However, the drawback of synchronized is that it modiifies the entire method and synchronizes every thread access. Synchronizing every time is obviously inefficient, so to improve on this, we have the following double-checked slob.

4. Double-check slob style (available, recommended)

public class Singleton {

    private static volatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if(instance == null) { instance = new Singleton(); }}}returninstance; }}Copy the code

This method uses two if judgments, also known as double-checks, and synchronizes code blocks instead of methods, which is more efficient and an improvement on the third method. Why judge twice? This is for the thread safety considerations, and the scene didn’t instantiate objects, A and B two threads simultaneously access static method and running at the same time to the first if statement, then thread A into the synchronized code block instantiation object first, after the end of thread B also enters the synchronized block, if there is no second if statement, Thread B will also instantiate the object.

5. Static inner classes (available, recommended)

public class Singleton {

    private Singleton() {}

    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        returnSingletonInstance.INSTANCE; }}Copy the code

The static inner class method is not instantiated immediately when the Singleton class is loaded. Instead, the SingletonInstance class is loaded when instantiation is required, and the object is instantiated by calling getInstance.

Also, because static properties of a class are initialized only the first time the class is loaded, objects in SingletonInstance are guaranteed to be instantiated only once, and this process is thread-safe.

6, enumeration (available, recommended)

public enum Singleton {
    INSTANCE;
}
Copy the code

This approach, promoted in Effective JAVA, solves two problems:

1) Thread safety issues. Because the Java virtual machine uses the ClassLoader method when loading enumeration classes, this method uses synchronized code blocks to ensure thread-safety.

2) Avoid deserializing objects, because deserialization of enumerations is not done by reflection.

Well, the singleton pattern of several ways to write is introduced here, and finally a simple summary of the advantages and disadvantages of the singleton pattern

Advantages and disadvantages of the singleton pattern

advantages

The singleton class has only one instance, saving memory resources. For some objects that need to be created and destroyed frequently, using singleton mode can improve system performance.

Singleton mode can set global access points in the system, optimize and share data, for example, the previous Web application page counter can use singleton mode to achieve the saving of the count value.

disadvantages

The singleton pattern generally has no interface, and there is basically no other way to extend it than to modify the code.