Design pattern-simple singleton

Design pattern-"simple" singleton

Overview

In some scenarios, for some classes, we often only need to instantiate an object. Such a class is called a singleton class. The created instance object is called a singleton object, such as the task manager in the operating system. System resource usage, if there are multiple objects at this time, you also need to maintain data consistency between multiple objects, but instead make the program processing cumbersome. Similarly, there are thread pools, caches, dialog boxes, registries, device driver objects, etc. that only need to be instantiated once.
From the perspective of the class structure alone, the singleton pattern may be the simplest design pattern, but it is still a little more elaborate when it comes to the details. The class structure diagram is shown in the following figure:
Singleton pattern structure diagram

The singleton pattern ensures that singleton classes are instantiated at most once and provides a global access point.


achieve

Hungry

The more direct and safe way is to privatize the construction method, construct an instance object internally, and provide a static access method to obtain a singleton object. The sample code is as follows:

package singleton;

public class EagerSingleton {
    private static EagerSingleton instance = new EagerSingleton();

    private EagerSingleton() {
    }

    public static EagerSingleton getInstance() {
        return instance;
    }

}

It can be seen that the internal instance object is created when the class is initialized, and the singleton class provides a static access method getInstance () for external access to the object. Hunger-style implementation is also called eager instantiation. This implementation is suitable for scenarios where the application always accesses instance objects or the objects do not take up too many resources when they are created and run.

Lazy

Correspondingly, in the case of lazy instantiaze, we only need to instantiate the singleton object for the first time, and then directly return the singleton object when accessing it later, which can prevent it To solve the problem of creating redundant objects when the system does not need to access the objects. The directly thought of implementation is as follows:

package singleton;

public class LazySingleton {
    private static LazySingleton instance = null;

    private LazySingleton() {
    }

    public static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

At this time, the problem encountered in a multi-threaded environment is that when the if judgment statement is executed at the same time, multiple objects are created, and a singleton cannot be guaranteed. Further, consider adding the synchronized keyword to the method to synchronize the method execution.

package singleton;

public class LazySingleton {
    private static LazySingleton instance = null;

    private LazySingleton() {
    }

    public static synchronized LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

Double check lock

The synchronized keyword, while ensuring thread synchronization, also brings inefficiency in obtaining object instances in multi-threaded situations, further improvement: narrowing the scope of synchronized statement blocks. If the entire if judgment statement block is kept in sync, each time an object is acquired, it needs to be kept in sync, to further narrow the scope of synchronization, and the implementation of double check locking is improved as follows:

package singleton;

public class LazySingleton {
    private volatile static LazySingleton instance = null;

    private LazySingleton() {
    }

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

Note: The above implementation methods have the risk of calling the private construction method through the reflection mechanism. You can further consider the judgment of adding the number of verification instances in the private construction method

Enumeration implementation

Perhaps the simplest singleton implementation method:

package singleton;

public enum Singleton {
    INSTANCE;
}

It concisely avoids the risk of multiple instantiations and provides a serialization mechanism for free. "Effective Java" even says that this method has become the best way to achieve Singleton.


summary

  1. The singleton pattern guarantees the uniqueness of singleton class objects. It has its specific application scenarios. Although there are multiple implementation methods, when you clarify their advantages and disadvantages, you will no longer be confused by these nouns;
  2. Although the structure of the singleton pattern is simple, it is not easy to instantiate an object, and there are many basic knowledge involved: the uniqueness guarantee when serializing, the role of volatile in multi-threaded programming, the limitation of class loaders, etc. , Xiaobian is also constantly accumulating.

References

"Large Design Patterns"
"Head First Design Patterns"
"Effective Java"
"Design Patterns Java Edition"
[How to write singleton patterns correctly]

PS: Singleton in CSDN

At the time of writing this article, I was severely tortured by the singleton application in CSDN. When using the markdown editor in CSDN to write to the end of the article, the same browser started to open another markdown editor page of CSDN. At this time, the original edit page was opened again, and the contents of the previously unsaved draft disappear Now ... I have to rewrite it / (ㄒ o ㄒ) / ~~ @CSDN, is this a bug? ? ?

Published 159 original articles · praised 225 · 210,000 views

Guess you like

Origin blog.csdn.net/lyg673770712/article/details/79635282