A pattern that generates only one instance is called a singleton pattern.

Blog address: blog.720uenterp rise and choose singleton – only one instance

When a program is running, it usually has many instances. For example, when we create 100 strings, we generate 100 instances of the String class.

Sometimes, however, we want only one instance of a class. For example, in “Guess what I draw”, users in a room need to share an instance of an artboard, rather than each user being assigned an instance of an artboard.

In addition, for the database connection, the thread pool, such as loading the configuration file parsing some very time-consuming and takes up the operation of the system resources, and there are frequent object creation and destruction, if every time to create an instance, the system overhead is very terror, so, we can always use a public example, to save system overhead.

A pattern like this that ensures that only one instance is generated is called a singleton pattern.

How to understand the singleton pattern

The purpose of the singleton pattern is that only one instance of a class exists, that is, to ensure the object uniqueness of a class in memory.

Now, let’s understand the class diagram.

Static class member variables

Static instance member variable defined by the Singleton class and initialized as an instance of the Singleton class. In this way, the singleton class is guaranteed to have only one instance.

Private constructor

The constructor of the Singleton class is private and is designed to prevent calls to the constructor from outside the class. The singleton pattern must ensure that only one instance can be generated in any case. To do this, you must make the constructor private. In other words, the Singleton class must create its own unique instance.

Global access method

The constructor is private, so we need to provide a global access method to an instance of the Singleton class.

Briefly define

Ensure that a class has only one instance and provide a global access method to access it.

The implementation of singleton pattern

The hungry type

As the name implies, a singleton is created as soon as the class loads the object.

public class Singleton {

    private static Singleton instance = new Singleton();

    private Singleton(){}

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

Note that the Singleton class is instantiated when static variables are defined, so Singleton objects can be created when the class is loaded.

At this point, we call the getInstance() method of the Singleton class twice to get the instance of the Singleton. We find that s1 and S2 are the same object.

public class SingletonTest {

    @Test
    public void getInstance(){
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();

        System.out.println("Instance object 1: + s1.hashCode());
        System.out.println("Instance object 2: + s2.hashCode());
        if (s1 ==  s2) {
            System.out.println("Instance equality");
        } else {
            System.out.println("Examples are not equal"); }}}Copy the code

LanHanShi

Lazy, that is, lazy loading. Singletons are instantiated when the getInstance() method is called for the first time. They are not instantiated automatically when the class is loaded. Instances are loaded when needed.

public class Singleton2 {

    private Singleton2(){}

    private static Singleton2 instance = null;

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

Lazy thread safety

In multithreading, if you create singletons in a lazy fashion, you can create multiple instances.

To avoid multiple threads calling the getInstance() method at the same time, we can use the synchronized keyword for thread locking to handle simultaneous access by multiple threads. Each class instance corresponds to a thread lock, and synchronized modified methods must acquire the lock of the class instance calling the method in order to execute; otherwise, the owning thread blocks. Once executed, the method monopolizes the lock and does not release it until it returns from the method. The blocked thread can then acquire the lock and re-enter the executable state.

public class Singleton3 {

    private Singleton3(){}

    private static Singleton3 instance = null;

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

The above example, which works well in multithreading and is thread-safe, requires a thread-lock judgment every time the getInstance() method is called, which can degrade system performance in a multi-threaded environment with high concurrent access. In fact, not only is it inefficient, 99% of the time thread locking judgments are not required.

At this point, we can use a double check lock to process. In other words, using a double check lock, the first time the instance is checked to see if it has been created, and if not, the singleton is created synchronously.

public class Singleton4 {

    private Singleton4(){}

    private static Singleton4 instance = null;

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

The enumeration

Enumerations are characterized by the fact that the constructors are private and the member object instances are predefined, so it is very convenient to implement the singleton pattern through enumerations.

public enum SingletonEnum {
    INSTANCE;
    private SingletonEnum(){}
}Copy the code

Static inner class

Singleton5 is not instantiated when the class is loaded. Instead, the inner class SigletonHolder is loaded on the first call to getInstance(), at which point instance member variables are initialized to ensure that objects in memory are unique.

public class Singleton5 {
    private Singleton5() {}

    private static class SigletonHolder {
        private final static Singleton5 instance = new Singleton5();
    }

    public static Singleton5 getInstance() {
        returnSigletonHolder.instance; }}Copy the code

Divergent thinking

How to transform into a singleton class

Suppose we now have a counting class Counter that counts the number of increments, each time the plus() method is called.

public class Counter {

    private long count = 0;

    public long plus(){
        return++count; }}Copy the code

The implementation of this example generates multiple instances, so how do we use the singleton pattern to ensure that only one instance object is generated?

In fact, I can achieve my requirements by breaking it down into three steps: static class member variables, private constructors, and global access methods.

public class Counter {

    private long count = 0;

    private static Counter counter = new Counter();

    private Counter(){}

    public static Counter getInstance(){
        return counter;
    }

    public synchronized long plus(){
        return++count; }}Copy the code

More case scenarios

Based on the singleton pattern, we can also extend the transformation, obtain a specified number of object instances, save system resources, and solve the problem of singleton sharing too much performance loss.

As an exercise, I now have a requirement that the implementation generate at most two instances of the Resource class, which can be accessed through the getInstance() method.

public class Resource {

    private int id = 0;

    private static Resource[] resource = new Resource[]{
        new Resource(1),
        new Resource(2)}; private Resource(int id){this.id = id;
    }

    public static Resource getInstance(int id){
        returnresource[id]; }}Copy the code

Singleton vs. static method

If you think of singleton patterns as non-static methods. The biggest difference between static methods and non-static methods is whether they are resident in memory, which is actually not true. They are resident in memory after the first load, so the method itself is in memory, there is no difference, so there is no static method resident in memory, non-static methods only allocate memory when used.

Therefore, we need to analyze the problem from the level of the scene. Consider using static classes, such as java.lang.Math, if a method has nothing to do with the instance object of its class and only provides global access. Using the singleton pattern is more object-oriented and allows you to extend the base class through inheritance and polymorphism. In addition, in the above case, the singleton pattern can be extended to give more control over the creation of instances.

The singleton pattern connects to the database

Database connections are not singletons, and if there is only one database connection instance in a system and all data access uses that connection instance, this design is bound to lead to performance defects. In fact, we use the singleton pattern to ensure that only one instance of the database connection pool exists, through which connection objects are allocated.

conclusion

The purpose of the singleton pattern is that only one instance of a class exists, that is, to ensure the object uniqueness of a class in memory.

If you use hungry, you instantiate the class as soon as it is loaded, so you don’t have to worry about multithreading safety, and the object is created from the start, which is better in terms of performance than lazy.

If lazy, lazy loading is used and instantiated on the first call to the getInstance() method. The advantage is that you don’t have to tie up system resources all the time and load instances as needed. However, to pay special attention to multi-threaded security, we need to consider using a double checklock scheme for optimization.

In fact, whether we should adopt the hungry-style or the slacker style depends on whether we want space to buy time or time to buy space.

Enumerations and static inner classes are also good implementations.

Refer to the article

(Book) graphic Design Pattern (Jie Chenghao)

The source code

Example Complete code: design-pattern-action

(after)

More wonderful articles, all in the “server-side thinking” wechat public account!