On the single example design mode of 23 design modes

Singleton mode

1. Introduction

Singleton pattern is one of the simplest forms of design pattern. The purpose of the first mock exam is to make one object of the class a unique instance in the system. To achieve this, you can start by instantiating it from the client. Therefore, we need to use a mechanism that only allows the generation of a unique instance of the object class to "block" all access to the object we want to generate. Use factory methods to limit the instantiation process. This method should be static (class method), because it makes no sense for an instance of a class to generate another unique instance.

2. Application scenario

For example, the counter of the website is generally implemented in the singleton mode. If you have multiple counters, the value of the counter will be refreshed for each user's access. In this way, the value of your real count is difficult to synchronize. However, if implemented in singleton mode, there will be no such problem, and thread safety problems can be avoided. Similarly, the design of multithreaded thread pool generally adopts single instance mode, because the thread pool needs to facilitate the control of threads in the pool

Similarly, the singleton mode is suitable for log applications of some applications or reading configuration files in web development. For example, HttpApplication is a typical singleton application.

3. Advantages and disadvantages

advantage:

  • There is only one object in memory to save memory space;
  • Avoid frequent creation and destruction of objects, which can improve performance;
  • Avoid multiple occupation of shared resources and simplify access;
  • Provide a global access point for the entire system.

Disadvantages:

  • Not applicable to objects with frequent changes;
  • Abusing singleton will bring some negative problems. For example, in order to save resources, designing database connection pool objects as singleton classes may lead to too many programs sharing connection pool objects and connection pool overflow;
  • If the instantiated object is not used for a long time, the system will consider the object as garbage and be recycled, which may lead to the loss of object state;

4. Implementation mode

4.1 hungry Han style

/**
 * Hungry Han style
 * After the class is loaded into memory, a singleton is instantiated, and the JVM ensures thread safety
 * Simple and practical, recommended!
 * The only drawback: instantiation is completed when the class is loaded, whether it is used or not
 */
public class Mgr01 {
    
    private static final Mgr01 INSTANCE = new Mgr01();

    private Mgr01() {};

    public static Mgr01 getInstance() {
        return INSTANCE;
    }

    public static void main(String[] args) {
        Mgr01 m1 = Mgr01.getInstance();
        Mgr01 m2 = Mgr01.getInstance();
        System.out.println(m1 == m2);
    }
}

It is recommended to use this method in development, which is simple and easy to use. If you pursue higher requirements, you can refer to the following lazy implementation methods.

4.2 lazy

/**
 * lazy loading
 * Also known as lazy style
 * Although it achieves the purpose of on-demand initialization, it brings the problem of thread insecurity
 * It can be solved by synchronized, but it also leads to a decrease in efficiency
 */
public class Mgr06 {
    
    private static volatile Mgr06 INSTANCE; //JIT

    private Mgr06() {
    }

    public static Mgr06 getInstance() {
        if (INSTANCE == null) {
            //duplication check
            synchronized (Mgr06.class) {
                if(INSTANCE == null) {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    INSTANCE = new Mgr06();
                }
            }
        }
        return INSTANCE;
    }

    public static void main(String[] args) {
        for(int i=0; i<100; i++) {
            new Thread(()->{
                System.out.println(Mgr06.getInstance().hashCode());
            }).start();
        }
    }
}

Double checking and locking part of the code at the same time have a little impact on the efficiency. I'm looking at another implementation

/**
 * Static inner class mode
 * JVM Guaranteed singleton
 * When the external class is loaded, the internal class will not be loaded, so lazy loading can be realized
 */
public class Mgr07 {

    private Mgr07() {
    }

    private static class Mgr07Holder {
        private final static Mgr07 INSTANCE = new Mgr07();
    }

    public static Mgr07 getInstance() {
        return Mgr07Holder.INSTANCE;
    }

    public static void main(String[] args) {
        for(int i=0; i<100; i++) {
            new Thread(()->{
                System.out.println(Mgr07.getInstance().hashCode());
            }).start();
        }
    }
}

In actual development, it can be selected according to the business scenario of the project.

Keywords: Design Pattern Singleton pattern

Added by PHPeter on Tue, 18 Jan 2022 00:25:20 +0200