Personal Technology Blog (IBLi)
CSDN making the nuggets
The singleton pattern
concept
Singleton pattern: A class has absolutely one instance in any case and provides a global access point (getInstance method). The implementation is basically to hide its constructor, and the singleton pattern is a creation pattern. Some practical application scenarios such as DBpool, ServletContext, ServletConfig, etc
Write in singleton mode
Hangry singleton
Create an instance when the singleton class is first loaded;
public class HungrySingleton {
private static final HungrySingleton hungrySingleton = new HungrySingleton();
private HungrySingleton(a){}
public static HungrySingleton getInstance(a){
returnhungrySingleton; }}Copy the code
advantages
1, high execution efficiency, without any lock
disadvantages
The class is initialized as soon as it is loaded. In some cases, this may cause memory waste. If there is a large number of classes, many classes will be initialized, occupying a large amount of memory;
limitations
Spring can’t be used, and when Spring starts, there’s a lot of class loading.
The second way to write hungry
public class HungryStaticSingleton {
private static final HungryStaticSingleton hungrySingleton ;
static {
hungrySingleton = new HungryStaticSingleton();
}
private HungryStaticSingleton(a){}
public static HungryStaticSingleton getInstance(a){
returnhungrySingleton; }}Copy the code
The difference is simply the order in which the classes are loaded.
Lazy singleton
An instance is created when it is called by an external class;
public class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton(a) {}public static LazySingleton getInstance(a) {
if (instance == null) {
instance = new LazySingleton();
}
returninstance; }}Copy the code
advantages
1, save memory
disadvantages
1. The real singleton cannot be guaranteed and the thread is not safe
Threads are unsafe for two reasons
- Subsequent threads overwrite instances created by previous threads
- At the same time, enter the judgment condition, return in order, when there is no overwrite, return the instance
Solutions:
public static synchorized LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
Copy the code
However, when the getInstance method adds a lock, performance degrades. If there are many requests, all threads except the one that acquired the lock will have to wait.
How to optimize?
public class LazyDclSingleton {
private static LazyDclSingleton instance = null;
private LazyDclSingleton(a) {}// The following thread overwrites the instance created by the previous thread
public static LazyDclSingleton getInstance(a) {
if (instance == null) {
synchronized (LazyDclSingleton.class) {
instance = newLazyDclSingleton(); }}returninstance; }}Copy the code
Double check lock
public class LazyDclSingleton {
private static volatile LazyDclSingleton instance = null;
private LazyDclSingleton(a) {}public static LazyDclSingleton getInstance(a) {
// Check whether to block
if (instance == null) {
synchronized (LazyDclSingleton.class) {
// Check whether you want to create an instance
if (instance == null) {
instance = newLazyDclSingleton(); }}}returninstance; }}Copy the code
limitations
Private static volatile LazyDclSingleton instance = null; (Volatile disallows instruction reordering)
Double-check the advantages and disadvantages of locks
advantages
1, high performance, can ensure thread safety
disadvantages
1, code readability check, not beautiful enough, code is not elegant enough
Static inner class writing
/** * Static inner classes * Static inner classes are only built when used * classPath:.. /LazyInnerClassSingleton.class * .. /LazyInnerClassSingleton$lazyholder.class * * Advantages: Elegant writing, using Java language syntax, high performance, avoid memory waste * * Disadvantages: can be broken by reflection */
public class LazyInnerClassSingleton {
private LazyInnerClassSingleton(a){}
public static LazyInnerClassSingleton getInstance(a){
return LazyHolder.instance;
}
private static class LazyHolder{
private static final LazyInnerClassSingleton instance = newLazyInnerClassSingleton(); }}Copy the code
advantages
1, elegant writing, the use of Java language syntax 2, high performance 3, avoid memory waste
disadvantages
1. Singletons can be destroyed by reflection
/** * Reflection breaks singleton mode */
public class ReflectTest {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class<? > clazz = LazyInnerClassSingleton.class; Constructor<? > declaredConstructor = clazz.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true); Object instance = declaredConstructor.newInstance(); System.err.println(instance); }}/ / print result com. Ibli. JavaBase. The pattern. The singleton. LazyInnerClassSingleton @ 38 af3868
Copy the code
Workaround: Add a judgment in the constructor to throw an exception to terminate the creation if the instance has already been created;
private LazyInnerClassSingleton(){
if (LazyHolder.instance != null){
throw new IllegalArgumentException();
}
}
Copy the code
Registered singleton
Each instance is cached in a container, and the instance is retrieved using a unique flag
The enumeration of writing
public enum EnumSingleton {
INSTANCE;
private Object object;
public Object getObject(a) {
return object;
}
public void setObject(Object object) {
this.object = object;
}
public static EnumSingleton getInstance(a){
returnINSTANCE; }}Copy the code
Use and test
public class EnumSingletonTest {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
EnumSingleton enumSingleton = EnumSingleton.getInstance();
enumSingleton.setObject(new Object());
// Try to use reflection destructionClass<? > clazz = EnumSingleton.class; Constructor<? > declaredConstructor = clazz.getDeclaredConstructor(String.class,int.class);
System.err.println(declaredConstructor);
declaredConstructor.setAccessible(true); Object object = declaredConstructor.newInstance(); System.err.println(object); }}Copy the code
Test results:
private com.ibli.javaBase.pattern.singleton.EnumSingleton(java.lang.String,int)
Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
at com.ibli.javaBase.pattern.singleton.EnumSingletonTest.main(EnumSingletonTest.java:17)
Copy the code
The reason is limited in the underlying JDK source code
@CallerSensitive public T newInstance(Object ... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (! override) { if (! Reflection.quickCheckMemberAccess(clazz, modifiers)) { Class<? > caller = Reflection.getCallerClass(); checkAccess(caller, clazz, null, modifiers); }} // Can't create enumeration type if ((clazz.getModifiers() & Modifier.ENUM)! = 0) throw new IllegalArgumentException("Cannot reflectively create enum objects"); ConstructorAccessor ca = constructorAccessor; // read volatile if (ca == null) { ca = acquireConstructorAccessor(); } @SuppressWarnings("unchecked") T inst = (T) ca.newInstance(initargs); return inst; }Copy the code
Advantages and disadvantages of enumeration
advantages
1, elegant writing, easy to use
disadvantages
2. As with hungry, it can cause a lot of memory waste in some cases
Container singletons
public class ContainerSingleton {
private ContainerSingleton(a) {}private static Map<String, Object> ioc = new ConcurrentHashMap<>();
public static Object getInstance(String className) {
Object instance = null;
if(! ioc.containsKey(className)) {try {
instance = Class.forName(className).newInstance();
ioc.put(className, instance);
} catch (Exception e) {
e.printStackTrace();
}
return instance;
} else {
returnioc.get(className); }}}Copy the code
The test class:
public class ContainerSingletonTest {
public static void main(String[] args) {
Object o1 = ContainerSingleton.getInstance("com.ibli.javaBase.pattern.singleton.Pojo");
Object o2 = ContainerSingleton.getInstance("com.ibli.javaBase.pattern.singleton.Pojo");
System.err.println(o1 == o2); // true}}Copy the code
Container singleton writing is suitable for scenarios where a large number of singleton instances are created, similar to Spring’s IOC container. Of course, there is a thread safety issue with the above method; // TODO
Serialization breaks the singleton pattern
/** * serialization: Convert the state of an object in memory to bytecode and then write the bytecode to disk as an IO output stream * deserialization: Read the persistent bytecode content into memory as an IO stream and then convert it into a Java object */
public class SerializableSingleton implements Serializable {
private static final SerializableSingleton serializableSingleton = new SerializableSingleton();
private SerializableSingleton(a) {}public static SerializableSingleton getInstance(a) {
returnserializableSingleton; }}Copy the code
The test class:
public class SerializableSingletonTest {
public static void main(String[] args) {
SerializableSingleton s1;
SerializableSingleton s2 = SerializableSingleton.getInstance();
FileOutputStream fos;
try {
fos = new FileOutputStream("SerializableSingleton.obj");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(s2);
oos.flush();
oos.close();
FileInputStream fis = new FileInputStream("SerializableSingleton.obj");
ObjectInputStream ois = new ObjectInputStream(fis);
s1 = (SerializableSingleton) ois.readObject();
ois.close();
System.out.println(s1);
System.out.println(s2);
System.out.println(s1 == s2);
} catch(Exception e) { e.printStackTrace(); }}}Copy the code
Results:
com.ibli.javaBase.pattern.singleton.SerializableSingleton@20ad9418
com.ibli.javaBase.pattern.singleton.SerializableSingleton@681a9515
false
Copy the code
Workaround: Add a method in SerializableSingleton
Private Object readResolve() {return serializableSingleton; }Copy the code
Results:
com.ibli.javaBase.pattern.singleton.SerializableSingleton@681a9515
com.ibli.javaBase.pattern.singleton.SerializableSingleton@681a9515
true
Copy the code
Reason: ois readObject (); The readResolve method is checked underneath, and if it does not exist, a new instance is generated using reflection;
ThreadLocal singleton
A relatively rare singleton pattern is described below
public class ThreadLocalSingleton {
private static final ThreadLocal<ThreadLocalSingleton> threadLocalSingleton =
new ThreadLocal<ThreadLocalSingleton>() {
@Override
protected ThreadLocalSingleton initialValue(a) {
return newThreadLocalSingleton(); }};private ThreadLocalSingleton(a){}
public static ThreadLocalSingleton getInstance(a){
returnthreadLocalSingleton.get(); }}Copy the code
public class ThreadLocalExector implements Runnable{
@Override
public void run(a) { System.err.println(ThreadLocalSingleton.getInstance()); }}Copy the code
Testing:
public class ThreadLocalSingletonTest {
public static void main(String[] args) {
System.out.println(ThreadLocalSingleton.getInstance());
System.out.println(ThreadLocalSingleton.getInstance());
Thread thread1 = new Thread(new ThreadLocalExector());
Thread thread2 = new Thread(newThreadLocalExector()); thread1.start(); thread2.start();; }}Copy the code
Results:
com.ibli.javaBase.pattern.singleton.ThreadLocalSingleton@38af3868 1
com.ibli.javaBase.pattern.singleton.ThreadLocalSingleton@38af3868 2
com.ibli.javaBase.pattern.singleton.ThreadLocalSingleton@10c69a60 3
com.ibli.javaBase.pattern.singleton.ThreadLocalSingleton@2f1eeb2f 4
Copy the code
Although the results of the above 3 and 4 are different, they actually achieve the effect of [singleton].
It’s too crowded at the bottom we’ll meet you higher.