The singleton pattern
The Singleton Pattern ensures that a class has absolutely one instance in all cases and provides a global access point. The singleton pattern is the creation pattern. The singleton pattern is also widely used in real life. For example, country president, company CEO, department manager, etc. In the J2EE standard, ServletContext, ServletContextConfig, etc. ApplicationContext in Spring framework applications; The database connection pools are also singletons.
The singleton mode can ensure that there is only one instance in memory and reduce the memory overhead. Multiple occupancy of resources can be avoided.
Singleton pattern characteristics
1. A singleton class can have only one instance; 2. A singleton class must create its own unique instance; 3. The singleton class must provide this instance to all other objects.
Common singleton patterns
There are many ways to write the singleton pattern. There are four main ones: hungry singleton, lazy singleton, enumeration singleton, and container singleton. (Enumeration singleton and container singleton are registered singleton.)
Hangry singleton
It is initialized immediately when the class is loaded and the singleton object is created. The IOC container ApplicationContext in Spring is itself a typical hanhan-like singleton
-
Advantages: no lock, high execution efficiency, in terms of user experience, better than the lazy style.
-
Disadvantages: the class is initialized when it is loaded. It takes up space when it is not used and wastes memory.
package org.about.designpatterns.singleton.hungry; / * * * @ Package org. About. Designpatterns. Singleton. Hungry * * @ @ the Author the Description the hungry singleton Immediately when I was in class loading initialization, and create a singleton. * Absolute thread safety, instantiated before threads exist, no thread safety problems * @version: V1.0 /public class HungrySingleton {/* * Define this singleton property/private static final HungrySingleton HUNGRY_SINGLETON; static { HUNGRY_SINGLETON = new HungrySingleton(); } /* * Private HungrySingleton() {// If (HUNGRY_SINGLETON! = null) {throw new RuntimeException(” not allowed to create more than one singleton “); Public static HungrySingleton getInstance() {return HUNGRY_SINGLETON; }// **/ * if the singleton implements Serializable serialization interface, to prevent Serializable singleton from breaking serialization, // private Object readResolve() {// private Object readResolve() {// private Object readResolve() HUNGRY_SINGLETON; / /}}
Lazy singleton
The inner class only loads the singleton when it is called by the outer class, avoiding the performance cost of creating instances at class load time
Double check lock writing
package org.about.designpatterns.singleton.lazy; / * * * @ Package org. About. Designpatterns. Singleton. Lazy * @ Author Epocher * @ Description idlers mode: double check the lock * < p > * knowledge: Volatile * (this) lazy = new LazyDoubleCheckSingleton(); * CPU execution of the above will translate into JVM instructions: 1. Allocate memory to this object; 2. Attribute initialization; 3. Reference to object * The above statement is non-atomic, so it may cause instruction rearrangement problem, namely: normally the execution order is 1->2->3, but in reality it may be 1->3->2 * * (1) In the case of single thread, instruction rearrangement has no impact; * (2) If thread (1) executes lazy = new LazyDoubleCheckSingleton() first 1 and then 3, * but thread (2) does not execute step 2. Thread 2 will return lazy if it does not meet the condition on the first check. Lazy = new LazyDoubleCheckSingleton(); Statements are executed in the order 1, 2, and 3 *. For details, see the characteristics of volatile. </p> * @date 2020-07-28 16:35 * @version: V1.0 */public class lazyDoublecheckleton {/** * Volatile */ private volatile static LazyDoubleCheckSingleton lazy; /** * private constructor */ private LazyDoubleCheckSingleton() {if (lazy! = null) {throw new RuntimeException(" Not allowed to create more than one singleton!" ); }} /** * provides globally unique access points * <p> * synchronized * </p> * @return lazy */ public static LazyDoubleCheckSingleton getInstance() {// If (lazy == null) {// if (lazy == null) {if (lazy == null) { Synchronized to ensure that only one thread enters the synchronized (LazyDoubleCheckSingleton. Class) {/ / the second check, if not check, so after the first thread to create the object lock is released, will create the object back into the object, If (lazy == null) {lazy = new LazyDoubleCheckSingleton(); } } } return lazy; }// **/ * if the singleton implements Serializable serialization interface, to prevent Serializable singleton from breaking serialization, // private Object readResolve() {// private Object readResolve() {// return lazy; / /}}Copy the code
Static inner class writing
Take advantage of static inner class loading: there is no automatic initialization, and static inner classes are loaded only when their methods, static fields, or constructors are called. Thread safety issues are cleverly avoided by using JVM low-level features. The performance is relatively excellent
package org.about.designpatterns.singleton.lazy; / * * * @ Package org. About. Designpatterns. Singleton. Lazy * * @ @ Author Description static inner class implements LanHanShi singleton performance should not used all the synchronized keyword * @Version: V1.0 */public class LazyInnerClassSingleton {/** * private LazyInnerClassSingleton(){// This is to prevent If (lazyholder.lazy! = null) {throw new RuntimeException(" Not allowed to create more than one singleton!" ); }} /** * global unique access point * static to make singleton space sharing * final to ensure that this method cannot be overridden, LAZY */ public static final LazyInnerClassSingleton getInstance() { Return lazyholder.lazy; } /** * Static inner classes take advantage of static inner class loading features * Internal classes are not automatically initialized. Static inner classes are loaded only when a static inner class's method, static field, or constructor is called. * The underlying logic of the JVM Private static class LazyHolder {private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton(); }// **/ * if the singleton implements Serializable serialization interface, to prevent Serializable singleton from breaking serialization, // private Object readResolve() {// private Object readResolve() {// private Object readResolve() LazyHolder.LAZY; / /}}Copy the code
Hungry and lazy
- Hungry type: time and space is a typical space, in time, when the class loading will create a class instance, whether you use, created first, then each call, there is no need to judge again, save the running time. Lazy: is a typical time for space, that is, every time an instance is acquired, the judgment will be made to see whether the instance needs to be created, wasting the judgment time. Of course, if no one ever uses it, the instance will not be created, saving memory space
- Thread-safe hanky-hank: Threads are absolutely safe because the object instance is initialized when the class is loaded. The JVM is only loaded once, creating a unique instance lazy before concurrency occurs: there is a thread-safety issue. A good solution is the above double-checked locking and static inner class writing
Registered singleton
Registered singletons: Also known as registered singletons, each instance is registered in a certain place, using a unique identifier to obtain the instance. Registered singletons are written in two ways: container cache and enumeration registry
Enumerated singleton
It not only solves the multi-thread synchronization problem, but also prevents deserialization from recreating new objects and reflection from destroying singletons. Because enumerations are handled separately at the bottom of Java. Enumerations appear later in JDK1.5, so the frequency of use is not particularly high, essentially also belongs to hungry singleton, but many books are recommended as a way of writing
package org.about.designpatterns.singleton.register; / * * * @ Package org. About. Designpatterns. Singleton. Register * * @ @ Author Description registered type: enumeration type singleton * @ Version: V1.0 */public enum enumleton {INSTANCE; private Object data; public Object getData() { return data; } public void setData(Object data) { this.data = data; } public static EnumSingleton getInstance() { return INSTANCE; }}Copy the code
Container singleton
The SpringIoc container is a registry singleton that actually maintains an instance of a singleton class, These instances are stored in a Map. Registered instances are directly returned from the Map. Unregistered instances are registered first and then returned. The internal implementation of the registered singleton is actually using hanhanian, because the static method block is instantiated when the class is loaded and there are thread safety issues if the singleton is unlocked
package org.about.designpatterns.singleton.register; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; / * * * @ Package org. About. Designpatterns. Singleton. Register * * @ @ Author Description container type singleton * @ Version: V1.0 */public class ContainerSingleton {/** * private ContainerSingleton() {} private static Map<String, Object> ioc = new ConcurrentHashMap<>(); Public static Object getBean(String className) {synchronized (ioc) {if (! ioc.containsKey(className)) { Object obj = null; Try {// Here is the simple factory pattern obj = class.forname (className).newinstance (); ioc.put(className, obj); } catch (Exception e) { e.printStackTrace(); } // create one if it doesn't exist, and return obj; Return ioc.get(className); }}}Copy the code
These are some of the more common singletons.
The last
Thank you for reading here, after reading what do not understand, you can ask me in the comments section, if you think the article is helpful to you, remember to give me a thumbs up, every day we will share Java related technical articles or industry information, welcome to pay attention to and forward the article!