Singleton mode, you do not know a thing ~ ~

Singleton pattern can be said to be as long as a qualified developers will write, but if you want to get to the bottom, a small singleton can involve many things, such as: multi-thread safe? Are lazy loading? Performance and so on. You know there are several written singleton it? How to prevent a single case of damage reflection mode?

A, singleton

1.1 Definitions

Singleton is in the program run only instantiated once, to create a globally unique object. A bit like  Java static variables, but Singleton pattern is superior to static variables:

  1. Static variables when the program starts JVMwill be loaded if not used, will cause waste of resources;
  2. Singleton pattern enables lazy loading, you can only go to create an instance when using instance.

Development tools, libraries Many tools are applied singleton mode, the proportion of the thread pool, cache, logs and other objects, they only need to create an object, if you create multiple instances, may lead to unpredictable problems, such as waste of resources, deal with inconsistent results and other issues.

1.2 The idea of ​​a single embodiment of

  1. Examples of static objects;
  2. Privatization of the constructor, create an instance by prohibiting construction method;
  3. It provides a public static method to return a unique instance.

The benefits of a single case of 1.3

  1. Only one object, spending less memory, good performance;
  2. Avoid multiple assignment of resources;
  3. Set global access point in the system, optimization and access to shared resources.

Second, the single-mode embodiment

  1. Starving mode
  2. Lazy mode
  3. Double-check lock mode
  4. Internal static type Singleton
  5. Example single-mode enumeration class

2.1 starving mode

When defining static property, directly instantiated object

public class HungryMode {

    /** * 利用静态变量来存储唯一实例 */ private static final HungryMode instance = new HungryMode(); /** * 私有化构造函数 */ private HungryMode(){ // 里面可以有很多操作 } /** * 提供公开获取实例接口 * @return */ public static HungryMode getInstance(){ return instance; } }

2.1.1 advantage

Due to the use of statickeywords to ensure that when referencing this variable, so on this variable write operations are complete, so to ensure the JVMthread safety level

2.1.2 shortcomings

Lazy loading can not be achieved, resulting in a waste of space: if a large analogy, when we initialized to load this class, but we did not use this class for a long time, which leads to a waste of memory space.

Therefore, not only can be used in  getInstance()the method, only to initialize the singleton class, it will load data singleton class. So there: lazy style .

2.2 lazy mode

Lazy mode is a lazy mode, does not create an instance when the program is initialized, will only create an instance when using the example, so lazy mode to solve the problem of wasted space caused by starving mode.

2.2.1 General to achieve lazy mode

public class LazyMode {
    /** * 定义静态变量时,未初始化实例 */ private static LazyMode instance; /** * 私有化构造函数 */ private LazyMode(){ // 里面可以有很多操作 } /** * 提供公开获取实例接口 * @return */ public static LazyMode getInstance(){ // 使用时,先判断实例是否为空,如果实例为空,则实例化对象 if (instance == null) { instance = new LazyMode(); } return instance; } }

But this realization in the case of multiple threads is unsafe, there may be multiple instances of circumstances occur:

if (instance == null) {
    instance = new LazyMode();
}

Suppose there are two threads into the above code, because there is no conservation measures, so two threads can determine simultaneously  instance are empty, will go to initialize an instance, so the situation there will be multiple instances.

Optimization 2.2.2 lazy mode

We give getInstance()methods add synchronizedkeywords that getInstance()method became a protected resource will be able to solve the problem of multiple instances.

public class LazyModeSynchronized {
    /** * 定义静态变量时,未初始化实例 */ private static LazyModeSynchronized instance; /** * 私有化构造函数 */ private LazyModeSynchronized(){ // 里面可以有很多操作 } /** * 提供公开获取实例接口 * @return */ public synchronized static LazyModeSynchronized getInstance(){ /** * 添加class类锁,影响了性能,加锁之后将代码进行了串行化, * 我们的代码块绝大部分是读操作,在读操作的情况下,代码线程是安全的 * */ if (instance == null) { instance = new LazyModeSynchronized(); } return instance; } }

2.2.3 Model advantage lazy

It implements lazy loading, saving memory space.

2.2.4 drawback lazy mode

  1. In the case of an unlocked, thread-safe, multiple instances may arise;
  2. In the case of locked, the program will serialization, the system has serious performance problems.

Lazy mode locking problems, for getInstance()the method, the vast majority of the operations are read operations, the read operation is thread-safe, so we will not let each thread must hold the lock before calling this method, we need to adjust locking problem. This also created a new implementation model: double check the lock mode .

2.3 double-check lock mode

2.3.1 double check the lock mode is generally realized

public class DoubleCheckLockMode {

    private static DoubleCheckLockMode instance; /** * 私有化构造函数 */ private DoubleCheckLockMode(){ } /** * 提供公开获取实例接口 * @return */ public static DoubleCheckLockMode getInstance(){ // 第一次判断,如果这里为空,不进入抢锁阶段,直接返回实例 if (instance == null) { synchronized (DoubleCheckLockMode.class) { // 抢到锁之后再次判断是否为空 if (instance == null) { instance = new DoubleCheckLockMode(); } } } return instance; } }

Double-check lock mode to solve a single case, performance, security thread, but such an approach is also problematic: in the case of multi-threaded, there may be a null pointer problem occurs because the problem is JVMin the instance of an object when it will be optimizing and reordering operation instructions.

2.3.2 What is the command rearrangement?

private SingletonObject(){
      // 第一步 int x = 10; // 第二步 int y = 30; // 第三步 Object o = new Object(); }

The above constructor SingletonObject(), JVM will it be an instruction reordering, the execution order may be a mess, but whether it is the kind of execution order, JVM and finally it will ensure the completion of all instances instantiated. If the constructor operation is relatively long, in order to improve efficiency, JVM will be at the inside of the constructor instantiated attributes are not completed, the object is returned . The reason double null pointer lock detection problem is to appear here, when one thread acquires the lock instantiated, direct access to other threads instance, due to the JVMreasons instruction reordering, the object of other threads may not get a complete objects, so when you use the instance will be null pointer exception problem .

2.3.3 double check the lock mode optimization

To solve the problem caused null pointer exception of double checks the lock mode, only need to use volatilekeywords, volatilekeyword strictly follow the happens-beforeprinciple that: before the read operation, write operation must be completed.

public class DoubleCheckLockModelVolatile {
    /** * 添加volatile关键字,保证在读操作前,写操作必须全部完成 */ private static volatile DoubleCheckLockModelVolatile instance; /** * 私有化构造函数 */ private DoubleCheckLockModelVolatile(){ } /** * 提供公开获取实例接口 * @return */ public static DoubleCheckLockModelVolatile getInstance(){ if (instance == null) { synchronized (DoubleCheckLockModelVolatile.class) { if (instance == null) { instance = new DoubleCheckLockModelVolatile(); } } } return instance; } }

2.4 static inner classes mode

Static inner classes mode is also called a single case of holders mode, create an instance of the inner class, because the  JVM will is in the process of loading external class, it is not loaded static inner classes, only internal properties of the class / method is called when load and initialize its static properties. Static properties of staticmodified to ensure only be instantiated once, and strictly ensure the instantiation order.

public class StaticInnerClassMode {

    private StaticInnerClassMode(){ } /** * 单例持有者 */ private static class InstanceHolder{ private final static StaticInnerClassMode instance = new StaticInnerClassMode(); } /** * 提供公开获取实例接口 * @return */ public static StaticInnerClassMode getInstance(){ // 调用内部类属性 return InstanceHolder.instance; } }

In this way a hungry man type way with the mechanism adopted similar, but different. Both such mechanisms are employed to ensure that loading only one thread instance initialization. different places:

  1. Starving formula manner as long as Singletonthe class is loaded will be instantiated, no Lazy-Loadingeffect;
  2. Static inner classes in the way Singletonwhen the class is loaded and instantiated not immediately, but when the need to instantiate, call the getInstance()method will load SingletonInstancethe class to complete Singletoninstantiation.

Static properties of the class is first loaded only when the class is initialized, so here, JVMto help us ensure the security thread, when the class is initialized, the other thread is inaccessible.

So in this way , without adding any locks to ensure the safety of multi-threaded, and did not waste any performance impact and space .

2.5 Enumeration class implements Singleton

Because an enumerated type is thread-safe, and only loaded once, designers full use of this feature to achieve enumeration singleton pattern, enumeration wording is very simple, but enumerated type is used to achieve a single case in CD eleven kinds of single embodiment mode of realization is not damaged .

public class EnumerationMode {
    
    private EnumerationMode(){ } /** * 枚举类型是线程安全的,并且只会装载一次 */ private enum Singleton{ INSTANCE; private final EnumerationMode instance; Singleton(){ instance = new EnumerationMode(); } private EnumerationMode getInstance(){ return instance; } } public static EnumerationMode getInstance(){ return Singleton.INSTANCE.getInstance(); } }

Applications:

  1. We need to create and destroy objects frequent;
  2. When you create an object consuming too much or spend too many resources, but frequently used objects;
  3. Tools objects;
  4. Object databases or frequently accessed files.

Third, the Singleton pattern of problems and solutions

Enumerating addition, other methods are destroyed by a single embodiment reflectively

Singleton pattern destroy 3.1

/**
 * 以静态内部类实现为例
 * @throws Exception
 */
@Test
public void singletonTest() throws Exception { Constructor constructor = StaticInnerClassMode.class.getDeclaredConstructor(); constructor.setAccessible(true); StaticInnerClassMode obj1 = StaticInnerClassMode.getInstance(); StaticInnerClassMode obj2 = StaticInnerClassMode.getInstance(); StaticInnerClassMode obj3 = (StaticInnerClassMode) constructor.newInstance(); System.out.println("输出结果为:"+obj1.hashCode()+"," +obj2.hashCode()+","+obj3.hashCode()); }

Print Console:

输出结果为:1454171136,1454171136,1195396074

From the results we can see the output obj1and obj2the same object, obj3a new object. obj3We are by reflection, which in turn calls a private constructor and then creates a new object.

3.2 How to prevent a single case of damage

In the configuration process can be determined, there Ruoyi instance, prevent the formation of a new instance, the solution as follows:

public class StaticInnerClassModeProtection {

    private static boolean flag = false; private StaticInnerClassModeProtection(){ synchronized(StaticInnerClassModeProtection.class){ if(flag == false){ flag = true; }else { throw new RuntimeException("实例已经存在,请通过 getInstance()方法获取!"); } } } /** * 单例持有者 */ private static class InstanceHolder{ private final static StaticInnerClassModeProtection instance = new StaticInnerClassModeProtection(); } /** * 提供公开获取实例接口 * @return */ public static StaticInnerClassModeProtection getInstance(){ // 调用内部类属性 return InstanceHolder.instance; } }

test:

/**
 * 在构造方法中进行判断,若存在则抛出RuntimeException
 * @throws Exception
 */
@Test
public void destroyTest() throws Exception { Constructor constructor = StaticInnerClassModeProtection.class.getDeclaredConstructor(); constructor.setAccessible(true); StaticInnerClassModeProtection obj1 = StaticInnerClassModeProtection.getInstance(); StaticInnerClassModeProtection obj2 = StaticInnerClassModeProtection.getInstance(); StaticInnerClassModeProtection obj3 = (StaticInnerClassModeProtection) constructor.newInstance(); System.out.println("输出结果为:"+obj1.hashCode()+"," +obj2.hashCode()+","+obj3.hashCode()); }

Print Console:

Caused by: java.lang.RuntimeException: 实例已经存在,请通过 getInstance()方法获取! at cn.van.singleton.demo.mode.StaticInnerClassModeProtection.<init>(StaticInnerClassModeProtection.java:22) ... 35 more

IV Summary

4.1 Comparison of various implementations of

name Starving mode Lazy mode Double-check lock mode Static inner class Enum class implementation
Availability Available Not recommended Recommended Use Recommended Use Recommended Use
Feature Lazy loading can not be achieved, it may result in a waste of space Unlock thread safe; lock poor performance Thread-safe; lazy loading; high efficiency Avoid thread unsafe, lazy loading, high efficiency. Writing simple; thread-safe; only loaded once

Reproduced original link: https://www.cnblogs.com/vandusty/p/11444293.html

Guess you like

Origin www.cnblogs.com/jichi/p/11448494.html