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:
- Static variables when the program starts
JVM
will be loaded if not used, will cause waste of resources; - 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
- Examples of static objects;
- Privatization of the constructor, create an instance by prohibiting construction method;
- It provides a public static method to return a unique instance.
The benefits of a single case of 1.3
- Only one object, spending less memory, good performance;
- Avoid multiple assignment of resources;
- Set global access point in the system, optimization and access to shared resources.
Second, the single-mode embodiment
- Starving mode
- Lazy mode
- Double-check lock mode
- Internal static type Singleton
- 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 static
keywords to ensure that when referencing this variable, so on this variable write operations are complete, so to ensure the JVM
thread 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 synchronized
keywords 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
- In the case of an unlocked, thread-safe, multiple instances may arise;
- 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 JVM
in 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 JVM
reasons 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 volatile
keywords, volatile
keyword strictly follow the happens-before
principle 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 static
modified 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:
- Starving formula manner as long as
Singleton
the class is loaded will be instantiated, noLazy-Loading
effect; - Static inner classes in the way
Singleton
when the class is loaded and instantiated not immediately, but when the need to instantiate, call thegetInstance()
method will loadSingletonInstance
the class to completeSingleton
instantiation.
Static properties of the class is first loaded only when the class is initialized, so here, JVM
to 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:
- We need to create and destroy objects frequent;
- When you create an object consuming too much or spend too many resources, but frequently used objects;
- Tools objects;
- 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 obj1
and obj2
the same object, obj3
a new object. obj3
We 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