Java Common Design Patterns——Singleton Pattern

Introduction to Singleton Pattern

More than 90% of the design patterns apply interfaces and abstract classes to a greater or lesser extent, while singletons are special and have no application of interfaces.

Objects of the database connection get class can be singletons.

A singleton means that there is only one object in memory. There is a difference between singleton and static. Static is used to modify member variables and member methods in a class, while singleton belongs to the object level.

Implementation of a singleton

Thinking: How to have only one object in memory? - The outside world cannot be arbitrarily instantiated (new). There is a concept called "private attributes and public methods" in the idea of ​​encapsulation, which is instantiated in the class that needs a singleton. These are the two conditions of a singleton: it cannot be instantiated by the outside world; it is private according to the encapsulated characteristic attributes, and the method is public.

The outside world cannot be instantiated. The way to achieve this is to set the constructor of the class that needs to be set as a singleton (hereinafter referred to as: singleton class) to private.

Note: If there are multiple virtual machines installed on the computer, it is not actually a singleton in the true sense, but each virtual machine has a singleton.

Lazy singleton pattern:

package design.pattern;

/**
 * Lazy singleton mode Demo<br>Lazy singleton is a behavior called at runtime.
 * The Singleton Pattern is one of the simplest design patterns in Java. <br>
 * This type of design pattern is a creational pattern, which provides an optimal way to create objects. <br>
 * This pattern involves a single class that is responsible for creating its own objects while ensuring that only a single object is created. <br>
 * This class provides a way to access its only object, which can be accessed directly without instantiating an object of this class. <br>
 *
 * 类名:LazySingleton<br>
 * Author: mht<br>
 * WeChat: baozoutianwa <br>
 * Date: March 18, 2018 - 8:41:01 pm<br>
 */
public class LazySingleton {

    /**
     * Property privatization
     */
    private static LazySingleton instance = null;

    /**
     * Constructor privatization
     */
    private LazySingleton() {
        System.out.println("This is the constructor: LazySingleton()");
    }

    /**
     * Public access to singleton object<br>
     * Author: mht<br>
     * Time: March 18, 2018 - 8:48:42 pm<br>
     */
    public synchronized static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }

        return instance;
    }
    
    public void doSomething() {
        System.out.println("LazySingleton is doing something now ...");
    }
}

The synchronized keyword is used to prevent multi-threading, that is, when multiple threads acquire instances of null at the same time, thereby creating multiple instances.

Hungry singleton pattern:

package design.pattern;

/**
 * Hungry singleton mode Demo<br>
 * The Singleton Pattern is one of the simplest design patterns in Java. <br>
 * This type of design pattern is a creational pattern, which provides an optimal way to create objects. <br>
 * This pattern involves a single class that is responsible for creating its own objects while ensuring that only a single object is created. <br>
 * This class provides a way to access its only object, which can be accessed directly without instantiating an object of this class. <br>
 *
 * 类名:EagerSingleton<br>
 * Author: mht<br>
 * WeChat: baozoutianwa <br>
 * Date: March 18, 2018 - 8:41:01 pm<br>
 */
public class EagerSingleton {

    /**
     * Property privatization
     */
    private static EagerSingleton instance = new EagerSingleton();

    /**
     * Constructor privatization
     */
    private EagerSingleton() {
        System.out.println("This is the constructor: LazySingleton()");
    }

    /**
     * Public access to singleton object<br>
     * Author: mht<br>
     * Time: March 18, 2018 - 8:48:42 pm<br>
     */
    public static EagerSingleton getInstance() {

        return instance;
    }
    
    public void doSomething() {
        System.out.println("EagerSingleton is doing something now ...");
    }
}

The difference between the Hungry singleton mode and the lazy one is that the timing of creating the object is different. The Hungry Han singleton will instantiate the object when the class is loaded, so as to avoid the situation of frequently judging whether the object is null under multi-threading, and the performance is better.

test:

package design.pattern;

public class TestSingleton {
    public static void main(String[] args) {
        
        EagerSingleton es0 = EagerSingleton.getInstance();
        EagerSingleton es1 = EagerSingleton.getInstance();
        
        System.out.println(es0);
        System.out.println(es1);
        System.out.println(es0 == es1);
    }
}

result:

This is the constructor: LazySingleton()
design.pattern.EagerSingleton@15db9742
design.pattern.EagerSingleton@15db9742
true

Lazy plus hungry singleton mode (private inner class implementation):

package design.pattern;

/**
 * Singleton mode for lazy and hungry combination
 * Lazy loading is implemented through private static inner classes
 * The advantage is that it can not only achieve lazy lazy loading, improve the loading speed of classes, avoid taking up too much memory at the beginning, but also have thread safety, no need to judge, and performance
 * will also be faster.
 * <br>类名:StaticInnerClass<br>
 * Author: mht<br>
 * Date: March 19, 2018 - 9:55:52 pm<br>
 */
public class StaticInnerClass {
    // Private static inner class, loaded on demand, loaded at time, that is, lazy loading
    private static class Holder{
        private static StaticInnerClass sic = new StaticInnerClass();
        private Holder() {
            System.out.println("This is the Holder constructor...");
        }
    }

    private StaticInnerClass() {
        System.out.println("This is the StaticInnerClass constructor...");
    }
    
    public static StaticInnerClass getInstance() {
        return Holder.sic;
    }
}

Double-checked singleton pattern (thread-safe lazy singleton):

package design.pattern;

/**
 * Double-checked singleton mode The practice of using double-checked synchronous lazy loading to create a singleton is a very good practice, which not only ensures the singleton (thread safety), but also improves the running efficiency of the program. <br>
 * 类名:DoubleCheckSingleton<br>
 * Author: mht<br>
 * Date: March 19, 2018 - 10:04:47 PM<br>
 */
public class DoubleCheckSingleton {
    /**
     * The Java language provides a slightly weaker synchronization mechanism, volatile variables, to ensure that other threads are notified of variable updates. When declaring a variable <br>
     When * is volatile, both the compiler and the runtime will notice that this variable is shared, so operations on this variable will not be reordered with other memory operations. <br>
     * Volatile variables are not cached in registers or invisible to other processors, so reading a volatile variable always returns the most recently written value. <br>
     * The specific meaning of the volatile keyword needs to be queried separately, and will not be explained too much here.
     */
    // Use the volatile keyword to prevent reordering because new Instance() is a non-atomic operation.
    private static volatile DoubleCheckSingleton dcs;

    private DoubleCheckSingleton() {

    }

    /**
     * In order to improve operating efficiency on the premise of ensuring singletons, we need to perform a second check on dcs, in order to avoid too many<br>
     * Synchronization (because the synchronization here only needs to be synchronized when the instance is created for the first time. Once the creation is successful, there is no need to synchronize to acquire the lock when acquiring the instance later). <br>
     * This practice is undoubtedly excellent, but we must pay attention to one thing:<br>
     * Singleton references must be decorated with the volatile keyword. <br>
     * Author: mht<br>
     * Time: March 19, 2018 - 10:14:37 pm<br>
     */
    public static DoubleCheckSingleton getInstance() {
        // Double-Check idiom
        if (dcs == null) {
            synchronized (DoubleCheckSingleton.class) {
                // only sync when the instance is first created
                if (dcs == null) {
                    dcs = new DoubleCheckSingleton();
                }
            }
        }

        return dcs;
    }
}

Register the singleton pattern:

package design.pattern;

import java.util.HashMap;
import java.util.Map;

/**
 * Register the singleton mode
 * <br>类名:RegisterSingleton<br>
 * Author: mht<br>
 * WeChat: baozoutianwa <br>
 * Date: March 18, 2018 - 10:03:27pm<br>
 */
public class RegisterSingleton<T> {

    /* registry */
    private static Map<String, Object> regMap = new HashMap<>();
    // During class loading, static initialization
    static{
        Connection conn = new Connection();
        UserService us = new UserService();
        // Initialize registry regMap
        regMap.put(conn.getClass().getName(), conn);
        regMap.put(us.getClass().getName(), us);
    }
    // private constructor
    private RegisterSingleton() {
        System.out.println("Register singleton pattern constructor...");
    }
   
    public synchronized static Object getInstance(String key) {
        if (key == null) return null;
        try {
            if (regMap.get(key) == null) {
                // Note here that this Demo uses the class name as the key to pass into the map, so the value passing here is also a related method, find the class through the class name, and then automatically instantiate it
                regMap.put(key, Class.forName(key).newInstance());
            }
            return regMap.get(key);
        } catch (ClassNotFoundException e) {
            e.printStackTrace ();
        } catch (InstantiationException e) {
            e.printStackTrace ();
        } catch (IllegalAccessException e) {
            e.printStackTrace ();
        }
        return null;
    }
}

test:

package design.pattern;

public class testSingleton {
    public static void main(String[] args) {
        UserService us = (UserService) RegisterSingleton.getInstance(UserService.class.getName());
        Connection conn1 = (Connection) RegisterSingleton.getInstance(Connection.class.getName());
        Connection conn2 = (Connection) RegisterSingleton.getInstance(Connection.class.getName());
        System.out.println(us);
        System.out.println(conn1);
        System.out.println(conn2);
        System.out.println(conn1 == conn2);
    }
}

operation result:

design.pattern.UserService@15db9742
design.pattern.Connection@6d06d69c
design.pattern.Connection@6d06d69c
true

Understanding of the application of the singleton pattern:

In the spring framework, most objects are used in a singleton mode. For example, the method classes UserDao and UserService to obtain the user User object are singletons, because in fact, what we really need is User instead of obtaining User. method class.

This also fully explains the implementation of @Autowired in Spring annotations to automatically inject objects. Carefully, we can also find that these automatically injected objects are generally intermediate class objects that implement a certain business, not the objects we need in the end. Therefore, in order to avoid frequent creation of these "middleware" objects, it is unnecessary to occupy The memory space is created in the form of a singleton. In addition, the database connection object Connection must also be a singleton.

Advantages of the singleton pattern:

1. There is only one object in memory, saving memory space

2. Avoid frequent creation and destruction of objects, which can improve performance

3. Avoid multiple occupation of shared resources and simplify access

4. Provide a global access point for the entire system

Application scenarios of the singleton pattern:

In computer systems, thread pools, caches, log objects, dialog boxes, printers, and graphics driver objects are often designed as singletons. In fact, these applications have more or less the function of resource managers.

Its core is to provide a unique instance for the entire system, and its application scenarios include but are not limited to the following:

1. Stateful tools

2. Objects that frequently access databases or files

refer to:

"A thorough understanding of the singleton pattern and its application in a multithreaded environment"


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325467673&siteId=291194637