There are six principles and twenty-three design patterns in design patterns. The six principles are single responsibility principle, open and close principle, Richter substitution principle, dependence inversion principle, interface isolation principle, Demeter principle. Twenty-three Design Mode: Singleton pattern, Builder Models, prototype pattern, factory method, abstract factory pattern, strategy pattern, state model, the chain of responsibility pattern, the interpreter, command mode, the observer pattern, memos, iterators, template method, the visitor pattern, mediation patterns, the proxy pattern, combination mode, the adapter pattern, decorative pattern, the flyweight pattern, appearance, bridge . Now let’s introduce the Singleton pattern.

Singleton

The singleton pattern is probably one of the most used design patterns in our development, and should be used by both experienced and novice programmers.

define

A class has one and only one instance, and its own instantiation is provided to the entire system.

Usage scenarios

Ensure that a class has only one object in the project to avoid creating too many objects and wasting resources. Such as:

  • Tools (time conversion, image loading, etc.)
  • Network request I/O operations

implementation

The singleton pattern can be implemented in many ways, such as:

  • Lazy – Threads are not safe
  • Slacker – Thread-safe
  • The hungry way
  • Double check the lock type
  • Registration type
  • The enumeration

Lazy – Threads are not safe

The most basic implementation, a thread context singleton, does not need to be shared with all threads or to add a lock such as Synchronize to improve performance.

  • The sample
/** * singleton mode */
public class Singleton {
    private static Singleton instance;
    // lazy - threads are not safe
    public static Singleton getInstance1(a){
        if (instance == null){
            instance = new Singleton();
        }
        returninstance; }}Copy the code

A fatal drawback, however, is that when getInstance1() is called in two identical threads at the same time, different Singleton objects are generated in the two threads. Singletons are quite useless. Since its thread is not safe, there is the following approach.

Slacker – Thread-safe

Coupled with a thread-safe lazy mode such as Synchronize, synchronization is relatively low and is not required most of the time.

  • The sample
/** * singleton mode */
public class Singleton {
    private static Singleton instance;
    // slacker - thread-safe
    public static synchronized Singleton getInstance2(a){
        if (instance == null){
            instance = new Singleton();
        }
        returninstance; }}Copy the code

Write it this way, it’s thread safe; However, because it is a synchronous method, it will be synchronized when called by multiple threads, which is inefficient. In order to improve efficiency in the process of use, we have the following methods

The hungry way

A global singleton instance is built at class load time. It is inherently thread-safe.

  • The sample
/** * singleton mode */
public class Singleton {
    / / the hungry
    private static Singleton instance2 = new Singleton();
    public static Singleton getInstance3(a){
        returninstance2; }}Copy the code

It’s thread-safe, but if I don’t use this class, because it was instantiated when the class was initialized, it’s just going to hold on to resources. In view of this situation, there is the following way.

Double check the lock type

The use of the synchronize keyword and the volatile keyword on a lazy basis ensures that there is no contention between threads during the first creation of multiple instances and synchronization occurs only during the first creation, which provides relatively high performance

  • The sample
/** * singleton mode */
public class Singleton {
    // Double check type
    private static volatile Singleton instance3;
    public static Singleton getInstance3(a){
        if (null == instance3){
            synchronized (Singleton.class){
                if (null == instance3){
                    instance3 = newSingleton(); }}}returninstance3; }}Copy the code

It is one of the most commonly used singletons in development. It is thread-safe and more efficient, but it is slow to load the first time and occasionally fails to load. There are also defects at high concurrency, although the probability is small. To optimize it, the following approach emerged.

Registration type

Exists as a global property of the create class, created when the create class is loaded.

  • The sample
/** * singleton mode */
public class Singleton {

    / / registration form
    public static Singleton getInstance4(a){
        return SingletonHolder.instance;
    }
    private static class SingletonHolder{
        private static final Singleton instance = newSingleton(); }}Copy the code

Instance is not initialized when a Singleton is first logged, only when getInstance4() is first called. It not only ensures thread-safety and object uniqueness, but also delays singleton instantiation. So it is also the most recommended singleton pattern which is also called the static inner class singleton pattern. There is also the container singleton pattern.

  • The sample
/** * singleton mode */
public class Singleton {
    // Register - container singleton mode
    private static Map<String, Object> singletonMap = new HashMap<String, Object>();
    public static Object getInstance5(Class clazz) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        String className = clazz.getName();
        if (ObjectUtils.isEmpty(className)){
            className = Singleton.class.getName();
        }
        if(! singletonMap.containsKey(className) ||null == singletonMap.get(className)){
            singletonMap.put(className, (Singleton)Class.forName(className).newInstance());
        }
        returnsingletonMap.get(className); }}Copy the code

In this way, multiple singleton types can be managed in a unified map, reducing the cost of our use. The implementation is also hidden from the user. Reduce coupling. Finally, enumeration singletons

The enumeration

Enumerated classes in Java are themselves a singleton pattern. The most important thing is that the creation of an enumerated instance is thread-safe, and in any case it is a singleton.

  • The sample
/** * enumerates singleton */
public enum SingletonEnum {
    INSTANCE;
    public void method(a){
        System.out.println("singleton"); }}public static void main(String[] args) {
    SingletonEnum.INSTANCE.method();
}
Copy the code

This approach is used sparingly, but it works really well without having to worry about serialization and deserialization. For other singleton deserialization, add a readResolve() function that returns a singleton instance.

    private Object readResolve(a){
        return instance;
    }
Copy the code

ReadResolve () is the hook function provided by deserialization. Prevents singletons from re-creating a new object during deserialization.

conclusion

Singleton pattern is often used in our development of a design pattern, we should use which way of singleton according to the actual needs to select, rather than blindly follow the trend. Learn more about design patterns to write elegant code.

demo

Reference: Baidu Encyclopedia – singleton mode “Android source code design mode analysis and practice”