Talking about the singleton pattern of the design pattern series

1. Features of singleton mode

  • Constructor privatization

  • Instantiated variable references are privatized;

  • The method of obtaining the instance is shared

2. Singleton mode application scenario

  • Only one instance of a class is allowed in the running of the whole program;

  • Objects that need to be instantiated and then destroyed frequently.

  • Objects that take too much time or resources to create but are frequently used.

  • An environment that facilitates resource communication with each other

3. N ways to write singleton mode in Java

This is the easiest way, the disadvantage is that the object will be instantiated when the class is loaded

1) Hungry Chinese style

/**
 * 饿汉式
 */
public class EaterSingleton {
    private static final EaterSingleton INSTANCE = new EaterSingleton();

    private EaterSingleton() {
    }

    public static EaterSingleton getInstance() {
        return INSTANCE;
    }
}

2). Lazy Mode - Double Verification

Thread safe, lazy initialization. This method uses a double-lock mechanism, which is safe and can maintain high performance in multi-threaded situations.

/**
 * 懒汉双重验证
 */
public class DoubleCheckSingleton {
    private  volatile static DoubleCheckSingleton INSTANCE = null;

    private DoubleCheckSingleton() {
    }

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

3). Static inner class - singleton mode

The JVM guarantees a single case, and the internal class will not be loaded when the external class is loaded, so that lazy loading can be achieved

package com.bytearch.designPattern.singleton;

/**
 * 内部类
 * 加载外部类时不会加载内部类
 */
public class AnonymousInnerClsSingleton {

    private AnonymousInnerClsSingleton() {
    }

    private static class LazyHolder {
        private final static AnonymousInnerClsSingleton INSTANCE = new AnonymousInnerClsSingleton();
    }

    public static AnonymousInnerClsSingleton getInstance() {
        return LazyHolder.INSTANCE;
    }
}

4). Enumerate singleton mode

It can not only solve thread synchronization, but also prevent deserialization. The enumeration singleton pattern is recommended in "Effective Java"

package com.bytearch.designPattern.singleton;

/**
 * 内部枚举类单例模式
 */
public class Singleton {
    private Singleton() {
    }

    /**
     * 静态枚举
     */
     enum SingletonEnum {

        INSTANCE;

        private Singleton singleton;

        SingletonEnum() {
            singleton = new Singleton();
        }

        private Singleton getInstance() {
            return singleton;
        }
    }

    public static Singleton getInstance() {
        return SingletonEnum.INSTANCE.getInstance();
    }

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

5. Container singleton pattern

/**
 * 容器式单例模式
 */
public class ContainerSingleton {
    private ContainerSingleton() {
    }
    private static Map<String, Object> singletonObjects = new ConcurrentHashMap<>();

    public static Object getBean(String className) {
        Object singletonObject = singletonObjects.get(className);
        if (singletonObject == null) {
            synchronized (singletonObjects) {
                singletonObject =  singletonObjects.get(className);
                if (singletonObject == null) {
                    try {
                        try {
                            singletonObject = Class.forName(className).newInstance();
                        } catch (InstantiationException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                        singletonObjects.put(className, singletonObject);
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return singletonObject;
    }

}

The container-style singleton pattern is used in the spring framework.

Let's take a look at the Spring source org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java

/**
  * Return the (raw) singleton object registered under the given name.
  * <p>Checks already instantiated singletons and also allows for an early
  * reference to a currently created singleton (resolving a circular reference).
  * @param beanName the name of the bean to look for
  * @param allowEarlyReference whether early references should be created or not
  * @return the registered singleton object, or {@code null} if none found
  */
 protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  Object singletonObject = this.singletonObjects.get(beanName);
  if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
   synchronized (this.singletonObjects) {
    singletonObject = this.earlySingletonObjects.get(beanName);
    if (singletonObject == null && allowEarlyReference) {
     ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
     if (singletonFactory != null) {
      singletonObject = singletonFactory.getObject();
      this.earlySingletonObjects.put(beanName, singletonObject);
      this.singletonFactories.remove(beanName);
     }
    }
   }
  }
  return (singletonObject != NULL_OBJECT ? singletonObject : null);
 }

4. Summary

  • There are many "variants" of the singleton mode. The above are some of the better implementations summarized (and they are all thread-safe). If you have a friend, you may wonder, which one should you use when there are so many? In fact, all of them can be used. Depending on your hobbies, the first type of "hungry Chinese style" may be used more often in work. Personally, I recommend "static inner class-singleton mode",

  • From the above, it is easy for everyone to find that the "container-style singleton mode" is also a variant of the "lazy man mode-double verification".

For example, I also use the "container singleton pattern" in the lightweight socket connection pool implementation .

public class ConnectionPool {
    /**
     * key is ip:port, value is ConnectionManager
     */
    private final static ConcurrentHashMap<String, ConnectionManager> CP = new ConcurrentHashMap<String, ConnectionManager>();

    public static Connection getConnection(InetSocketAddress socketAddress) throws MyException {
        if (socketAddress == null) {
            return null;
        }
        String key = getKey(socketAddress);
        ConnectionManager connectionManager;
        connectionManager = CP.get(key);
        if (connectionManager == null) {
            synchronized (ConnectionPool.class) {
                connectionManager = CP.get(key);
                if (connectionManager == null) {
                    connectionManager = new ConnectionManager(socketAddress);
                    CP.put(key, connectionManager);
                }
            }
        }
        return connectionManager.getConnection();
    }
    
}

5. Support

If you think this content is very inspiring to you, I would like to ask you to do two small favors:

  1. Click [Looking/Forwarding] , so that more people can see this content (If you like it or not, click Watching/Forwarding, it’s all hooliganism????)

  2. Pay attention to the official account [Talk about the structure] , the background of the official account will reply the following "number" or "keyword", and send you a full set of learning materials suitable for you.

    101: Java Elementary

    102: Advanced Java Advanced

    103: Java Interview

Talking about Architecture

Guess you like

Origin blog.csdn.net/weixin_38130500/article/details/106632441