When it comes to common design patterns, a lot of design patterns come to mind, singletons, factories, listeners, etc. There are 23 classic design patterns, but if you don't understand singletons, you don't understand singletons. Saying you have deep insights into other design patterns is not convincing. Now let's talk about design patterns from singletons!Copy the code

The concept of singleton design patterns

1. If a class is allowed to create only one object (or instance), that class is a singleton class. This design pattern is called the singleton design pattern, or singleton pattern for short.Copy the code

Implementation of singleton design pattern

The most common implementations of the singleton pattern are hungrier and slacker. But there are other ways to implement it!Copy the code
  1. Hungry: When the class is loaded, the instance is initialized.
public class Singleton { private static final Singleton singleton = new Singleton(); Private Singleton getInstance(){} public static Singleton getInstance(){return Singleton; }}Copy the code
  1. Lazy: Lazy has an advantage over hungry in that it supports lazy loading
/** * public class Singleton {private static Singleton; Private Singleton getInstance(){} public static Singleton getInstance(){if (Singleton == null) { Synchronized (Singleton) {if (Singleton == null) {Singleton = new Singleton(); } } } return singleton; }}Copy the code
  • Tips: There are some problems with this implementation. Because instructions are reordered, they may be used by another thread before they can be initialized. The solution is to add the volatile keyword. In fact, older versions of Java already solve this problem in JDK internal implementations.

  • Usage analysis:

    • Hangry, because it does not support lazy loading, will make the instance consume more resources or take a long time to initialize.
    • Slacker has an advantage over hungrier in that it supports lazy loading.
    • Personally, I prefer to use hangry. The reason is that if resources are consumed or the loading time is too long, the system performance will be affected, resulting in timeout or OOM. We can solve such situation at the beginning of the program, and it may lead to production accidents in production.
  1. Static inner class
Public class Singleton {private Singleton() {} private static class SingletonHolder{private static final Singleton instance = new Singleton(); } public static Singleton getInstance() {return singletonholder.instance; }}Copy the code
  • When the external class is loaded, it does not need to load the inner class immediately. If the inner class is not loaded, it does not initialize INSTANCE, so it does not occupy memory. This method not only ensures thread-safety, but also ensures singleton uniqueness, while delaying singleton instantiation.
  1. Enumeration (enum)
/** * public enum Singleton {INSTANCE; }Copy the code

Application of singleton pattern

How is the singleton pattern implemented in the frameworkCopy the code
  • Tips: Spring dependency injection Bean instances are singletons by default.
  • Spring’s Dependency injection AbstractBeanFactory getBean
	@Override
	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}
Copy the code

Next look at doGetBean(name, NULL, NULL, false);

/** * 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 */ @Nullable 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; }Copy the code

Singleton module differences

  1. Intra-thread singleton
  • A new entity is created within each thread, and the ThreadLocal utility class is provided in Java. Thread-unique singletons can be easily implemented.
  • Do it yourself:
Public class Singleton {private static final ConcurrentHashMap<Long, Singleton> instances = new ConcurrentHashMap<>(); Private Singleton(){} /** ** @return getInstance */ public static Singleton getInstance() {Long currentThreadId = Thread.currentThread().getId(); instances.putIfAbsent(currentThreadId, new Singleton()); return instances.get(currentThreadId); }}Copy the code
  1. Intra-process singleton
  • A properly implemented singleton class is unique within a process.
  1. Cluster environment singleton
  • Singleton objects are serialized and stored in external shared storage, such as redis or files