Look at the company code when the project was found in a lot of applications Singleton, Singleton pattern and found two used or implemented differently, then the Singleton pattern in the end there are several written it? Singleton pattern looks simple, but it was actually written a lot of problems
This article outlines
- What is a singleton
- Starving singleton object type to create
- Create a singleton object lazy style
- The advantages and disadvantages of singleton
- Examples of single-mode application scenario
What is a singleton
Make sure that a class has only one instance , and to instantiate and provide the example of the whole system, and there are two ways to create a Chinese-style creation is hungry, another is the lazy man's creation
Hungry man style create a singleton
Hungry man is the type to create objects had been created when the class is loaded, and not when needed to create objects
public class HungrySingleton {
private static HungrySingleton hungrySingleton = new HungrySingleton();
/**
* 私有构造函数,不能被外部所访问
*/
private HungrySingleton() {}
/**
* 返回单例对象
* */
public static HungrySingleton getHungrySingleton() {
return hungrySingleton;
}
}
复制代码
Description:
- Constructors privatization, to ensure the outside can not call the constructor to create an object, create an object's behavior can only be determined by the class
- Only by
getHungrySingleton
acquiring object methods HungrySingleton
Object has been created [created when the class loader]
Disadvantages:
- If you
getHungrySingleton
have not used to, a waste of resources
advantage:
- By the
ClassLoad
guarantee thread safety
Create singleton lazy formula
Lazy man's creation is the first time you need to create the object
-
Lazy singleton object type created with errors
could be easily modified on the basis of the above starving the definition of formulapublic class LazySingleton { private static LazySingleton lazySingleton = null; /** * 构造函数私有化 * */ private LazySingleton() { } private static LazySingleton getLazySingleton() { if (lazySingleton == null) { return new LazySingleton(); } return lazySingleton; } } 复制代码
Description:
- Constructors privatization
- When you need [
getLazySingleton
time] was to create a method call ah, it seems no problem, but when there are multiple threads simultaneously callgetLazySingleton
upon the method, the object is not initialized at this time just two threads simultaneously bylazySingleton == null
check, it will create twoLazySingleton
objects. Means must point out thegetLazySingleton
method is thread safe
-
synchronize
OrLock
it is easy to think of usingsynchronize
orLock
method for locking
usesynchronize
:public class LazySynchronizeSingleton { private static LazySynchronizeSingleton lazySynchronizeSingleton= null; /** * 构造函数私有化 * */ private LazySynchronizeSingleton() { } public synchronized static LazySynchronizeSingleton getLazySynchronizeSingleton() { if (lazySynchronizeSingleton == null) { lazySynchronizeSingleton = new LazySynchronizeSingleton(); } return lazySynchronizeSingleton; } } 复制代码
Use
Lock
:public class LazyLockSingleton { private static LazyLockSingleton lazyLockSingleton = null; /** * 锁 **/ private static Lock lock = new ReentrantLock(); /** * 构造函数私有化 * */ private LazyLockSingleton() { } public static LazyLockSingleton getLazyLockSingleton() { try { lock.lock(); if (lazyLockSingleton == null) { lazyLockSingleton = new LazyLockSingleton(); } } finally { lock.unlock(); } return lazyLockSingleton; } } 复制代码
Although these two methods to ensure the security thread, but poor performance because the threads of insecurity is mainly caused by this code:
if (lazyLockSingleton == null) { lazyLockSingleton = new LazyLockSingleton(); } 复制代码
Method to lock regardless of whether the object has been initialized will cause the thread to block. If the object is
null
only to be locked case, the object is notnull
the time were not locked, then the performance will be enhanced and double check the lock can achieve this demand -
Double lock check
first before locking determinelazyDoubleCheckSingleton == null
whether the establishment, if not established a direct return to the created objects, set up in lockpublic class LazyDoubleCheckSingleton { /** * 使用volatile进行修饰,禁止指令重排 * */ private static volatile LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null; /** * 构造函数私有化 * */ private LazyDoubleCheckSingleton() { } public static LazyDoubleCheckSingleton getLazyDoubleCheckSingleton() { if (lazyDoubleCheckSingleton == null) { synchronized (LazyDoubleCheckSingleton.class) { if (lazyDoubleCheckSingleton == null) { lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton(); } } } return lazyDoubleCheckSingleton; } } 复制代码
Description:
- Why do we need to
lazyDoubleCheckSingleton
be addedvolatile
as a modifierlazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
is not atomic, divided into three steps:- To
lazyDoubleCheckSingleton
allocate memory - Call the constructor to initialize
- The
lazyDoubleCheckSingleton
object pointing to the allocated memory [Executive completion of this steplazyDoubleCheckSingleton
will notnull
]
- To
In order to improve the efficiency of the program, the compiler will perform a rearrangement instruction, steps 2 and three have been rearranged, a first thread and a step of performing the three steps, executed,
lazyDoubleCheckSingleton
is notnull
, then the execution thread 2if (lazyDoubleCheckSingleton == null)
, thread 2 will likely not return directly to initialize the correctlazyDoubleCheckSingleton
object. The main reason for the error islazyDoubleCheckSingleton
not properly initialized completed [write], but other thread has readlazyDoubleCheckSingleton
the value of [reading], usevolatile
may prohibit instruction reordering, through the memory barrier to ensure that does not call read before writing [Executiveif (lazyDoubleCheckSingleton == null)
]Disadvantages:
- In order to ensure thread-safe code is not elegant too bloated
- Why do we need to
-
Static inner classes
public class LazyStaticSingleton { /** * 静态内部类 * */ private static class LazyStaticSingletonHolder { private static LazyStaticSingleton lazyStaticSingleton = new LazyStaticSingleton(); } /** * 构造函数私有化 * */ private LazyStaticSingleton() { } public static LazyStaticSingleton getLazyStaticSingleton() { return LazyStaticSingletonHolder.lazyStaticSingleton; } } 复制代码
Static inner classes will be initialized when you call, so is the lazy man,
LazyStaticSingleton lazyStaticSingleton = new LazyStaticSingleton();
appears to be a hungry man type, but only callsgetLazyStaticSingleton
will be initialized when the thread-safe by theClassLoad
guarantee, without thinking how locked
In front of several ways to achieve a single way of example, although have advantages and disadvantages, but basically a singleton thread safety. But there are people who could not understand singleton thrift role, it carried out the attack. It is nothing more than an attack to create more than one class, java
the subject methods are created new
, clone
serialization, reflection. The constructor can not be created through the privatization of new objects, while singleton class does not implement Cloneable
the interface by not clone
creating an object method, the rest of the attack that attacks only the reflection and serialization attacked
reflection attacks:
public class ReflectAttackTest {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//静态内部类
LazyStaticSingleton lazyStaticSingleton = LazyStaticSingleton.getLazyStaticSingleton();
//通过反射创建LazyStaticSingleton
Constructor<LazyStaticSingleton> constructor = LazyStaticSingleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
LazyStaticSingleton lazyStaticSingleton1 = constructor.newInstance();
//打印结果为false,说明又创建了一个新对象
System.out.println(lazyStaticSingleton == lazyStaticSingleton1);
//synchronize
LazySynchronizeSingleton lazySynchronizeSingleton = LazySynchronizeSingleton.getLazySynchronizeSingleton();
Constructor<LazySynchronizeSingleton> lazySynchronizeSingletonConstructor = LazySynchronizeSingleton.class.getDeclaredConstructor();
lazySynchronizeSingletonConstructor.setAccessible(true);
LazySynchronizeSingleton lazySynchronizeSingleton1 = lazySynchronizeSingletonConstructor.newInstance();
System.out.println(lazySynchronizeSingleton == lazySynchronizeSingleton1);
//lock
LazyLockSingleton lazyLockSingleton = LazyLockSingleton.getLazyLockSingleton();
Constructor<LazyLockSingleton> lazyLockSingletonConstructor = LazyLockSingleton.class.getConstructor();
lazyLockSingletonConstructor.setAccessible(true);
LazyLockSingleton lazyLockSingleton1 = lazyLockSingletonConstructor.newInstance();
System.out.println(lazyLockSingleton == lazyLockSingleton1);
//双重锁检查
LazyDoubleCheckSingleton lazyDoubleCheckSingleton = LazyDoubleCheckSingleton.getLazyDoubleCheckSingleton();
Constructor<LazyDoubleCheckSingleton> lazyDoubleCheckSingletonConstructor = LazyDoubleCheckSingleton.class.getConstructor();
lazyDoubleCheckSingletonConstructor.setAccessible(true);
LazyDoubleCheckSingleton lazyDoubleCheckSingleton1 = lazyDoubleCheckSingletonConstructor.newInstance();
System.out.println(lazyDoubleCheckSingleton == lazyDoubleCheckSingleton1);
}
}
复制代码
Based on static inner classes and synchronize
can create locked singleton object created by the reflection of the way the way the new object, there is reflection attacks, and the rest to create a singleton object several ways to use reflection to create new objects will be thrown
Deserialization attacks:
public class SerializableAttackTest {
public static void main(String[] args) {
//懒汉式
HungrySingleton hungrySingleton = HungrySingleton.getHungrySingleton();
//序列化
byte[] serialize = SerializationUtils.serialize(hungrySingleton);
//反序列化
HungrySingleton hungrySingleton1 = SerializationUtils.deserialize(serialize);
System.out.println(hungrySingleton == hungrySingleton1);
//双重锁
LazyDoubleCheckSingleton lazyDoubleCheckSingleton = LazyDoubleCheckSingleton.getLazyDoubleCheckSingleton();
byte[] serialize1 = SerializationUtils.serialize(lazyDoubleCheckSingleton);
LazyDoubleCheckSingleton lazyDoubleCheckSingleton11 = SerializationUtils.deserialize(serialize1);
System.out.println(lazyDoubleCheckSingleton == lazyDoubleCheckSingleton11);
//lock
LazyLockSingleton lazyLockSingleton = LazyLockSingleton.getLazyLockSingleton();
byte[] serialize2 = SerializationUtils.serialize(lazyLockSingleton);
LazyLockSingleton lazyLockSingleton1 = SerializationUtils.deserialize(serialize2);
System.out.println(lazyLockSingleton == lazyLockSingleton1);
//synchronie
LazySynchronizeSingleton lazySynchronizeSingleton = LazySynchronizeSingleton.getLazySynchronizeSingleton();
byte[] serialize3 = SerializationUtils.serialize(lazySynchronizeSingleton);
LazySynchronizeSingleton lazySynchronizeSingleton1 = SerializationUtils.deserialize(serialize3);
System.out.println(lazySynchronizeSingleton == lazySynchronizeSingleton1);
//静态内部类
LazyStaticSingleton lazyStaticSingleton = LazyStaticSingleton.getLazyStaticSingleton();
byte[] serialize4 = SerializationUtils.serialize(lazySynchronizeSingleton);
LazyStaticSingleton lazyStaticSingleton1 = SerializationUtils.deserialize(serialize4);
System.out.println(lazyStaticSingleton == lazyStaticSingleton1);
}
}
复制代码
The results are printed false
, deserialization attacks exist
for reflection attacks we can only choose to abandon the use of a single case of the existence of such defects way to create, but the counter-attack sequence, then it's still in the rescue, rescue posture as follows:
private Object readResolve() {
return lazySynchronizeSingleton;
}
复制代码
Add readResolve
method and return singleton object created, as the principle of rescue, you can follow SerializationUtils.deserialize
known code. The above-mentioned manner singleton object is necessary to consider thread safety, but also consider the attack, but by enumerating create singleton object nothing to worry about these issues
- enumerate
Code implementation is quite beautiful, a total of onlypublic enum EnumSingleton { INSTANCE; public static EnumSingleton getEnumSingleton() { return INSTANCE; } } 复制代码
8
line on behalf of the
realization of the principle: enumeration class field (field) is in fact the appropriate enum type of an instance of an object
can refer to: implementingLearn-Singleton-with-AN-enum-in-the Java
Singleton pattern advantage
- Only creates an instance to save memory overhead
- Reducing the performance overhead of the system, create a certain impact on the performance of the object to be recovered has
- Avoid multiple assignment of resources
- In the system set global access points, optimize and share resources optimization
Summarize what is to save resources, improve performance
Disadvantage of singleton
- Does not apply to objects for change
- No single model abstraction layer embodiment, extended with difficulty
- And the principle of a single conflict. A class should implement only a logical, not on whether it is a single case, is not a single case should be decided by the business
Examples of single-mode application scenario
Spring IOC
Singleton pattern is created using the defaultbean
- When you create an object needs to consume too many resources
- Static constant need to define a large number of static methods and environments, such as tools [feeling] is the most common scenario
summary
A total of six introduced to create a singleton object right way, create recommended starving singleton object type way, if there is demand for resources, it is recommended to use a static inner classes [Note] deserialization attack, otherwise the guarantee thread-safe while performance will be affected. The enumeration class is actually very good, thread-safe, there is no reflection of attack and counter-attack sequence, but feel this way create less singleton application, the company code is used to check and double lock there is anti-static inner classes [ serialization attack] to create a single way of example, when the interviewer before the interview even let out to write a single example, I use the enumeration way, the interviewer did not know there is this way
Last Attachment: Full test code example code +
Welcome fork with star