Writing examples of 7 singleton modes in Java version
preface
Today, I saw a sentence in an article. Add V before single example DCL. Let me take a closer look at the singleton mode again.
The singleton pattern in Java is one of the design patterns we have always used and often used. Everyone is very familiar with it, so this article is only for my own memory.
Singleton pattern is one of the simplest design patterns in Java. This type of design pattern belongs to creation pattern, which provides the best way to create objects.
The singleton pattern involves a single class that is responsible for creating its own objects while ensuring that only a single object is created. This class provides a way to access its unique object, which can be accessed directly without instantiating the object of this class.
Seven writing methods of singleton mode in Java version
1: Lazy, thread unsafe
This way of writing lazy loading is obvious, but the fatal thing is that multithreading does not work properly.
public class Singleton{ private static Singleton instance; private Singleton(){}; public static Singleton getInstance(){ if (instance == null) { instance = new Singleton(); } return instance; } }
2: Lazy, thread safe
This writing method can work well in multithreading, and it also seems to have a good lazy loading. Unfortunately, the efficiency is very low, and synchronization is not required in 99% of cases.
public class Singleton{ private static Singleton instance; private Singleton(){}; public static synchronized Singleton getInstance(){ if (instance == null) { instance = new Singleton(); } return instance; } }
3: Hungry man
This method is based on the classloder mechanism and avoids the synchronization problem of multiple threads. However, instance is instantiated when class loading. Although there are many reasons for class loading, most of them call getInstance method in singleton mode, However, it is not certain that there are other ways (or other static methods) to cause class loading. At this time, initializing instance obviously does not achieve the effect of lazy loading.
public class Singleton{ private static Singleton instance = new Singleton(); private Singleton(){}; public static Singleton getInstance(){ return instance; } }
4: Hungry man, variant
On the surface, there seems to be a big difference. In fact, it is similar to the third method, which is to instantiate instance during class initialization.
public class Singleton{ private static Singleton instance = null; private Singleton(){}; static { instance = new Singleton(); } public static Singleton getInstance(){ return instance; } }
5: Static inner class
This method also uses the classloder mechanism to ensure that there is only one thread when initializing the instance, It is different from the third and fourth methods (slight difference): the third and fourth methods are that as long as the singleton class is loaded, the instance will be instantiated (the lazy loading effect is not achieved). In this way, the singleton class is loaded, and the instance is not necessarily initialized. Because the singletonholder class is not actively used, the singletonholder class will be loaded only when the getInstance method is called, so as to instantiate the instance. Imagine that if instantiating an instance consumes resources, I want it to be delayed Late loading. On the other hand, I don't want to instantiate the singleton class when it is loaded, because I can't ensure that the singleton class may be actively used and loaded in other places, so it's obviously inappropriate to instantiate instance at this time. At this time, this method is very reasonable compared with the third and fourth methods.
public class Singleton{ private static class SingletonHolder{ private static final Singleton INSTANCE = new Singleton(); } private Singleton(){}; public static Singleton getInstance(){ return SingletonHolder.INSTANCE; } }
It seems that static inner classes seem to be the most perfect method. In fact, they are not. There may be reflection attacks or deserialization attacks. See the following code:
public static void main(String[] args) throws Exception { Singleton singleton = Singleton.getInstance(); Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor(); constructor.setAccessible(true); Singleton newSingleton = constructor.newInstance(); System.out.println(singleton == newSingleton); }
6: Enumeration
This method is advocated by Josh Bloch, the author of effective Java. The best singleton implementation mode is enumeration mode. Using the enumeration feature, let the JVM help us ensure thread safety and single instance problems, and prevent deserialization and re creation of new objects. In addition, the writing method is particularly simple.
public enum Singleton { INSTANCE; public void get() { System.out.println(""); } }
Through decompilation, we can see that enumeration is the creation of objects in static blocks.
public final class com.loadclass.test.Singleton extends java.lang.Enum<com.loadclass.test.Singleton> { public static final com.loadclass.test.Singleton INSTANCE; public static com.loadclass.test.Singleton[] values(); Code: 0: getstatic #1 // Field $VALUES:[Lcom/loadclass/test/Singleton; 3: invokevirtual #2 // Method "[Lcom/loadclass/test/Singleton;".clone:()Ljava/lang/Object; 6: checkcast #3 // class "[Lcom/loadclass/test/Singleton;" 9: areturn public static com.loadclass.test.Singleton valueOf(java.lang.String); Code: 0: ldc #4 // class com/loadclass/test/Singleton 2: aload_0 3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum; 6: checkcast #4 // class com/loadclass/test/Singleton 9: areturn public void get(); Code: 0: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #8 // String 5: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return static {}; Code: 0: new #4 // class com/loadclass/test/Singleton 3: dup 4: ldc #10 // String INSTANCE 6: iconst_0 7: invokespecial #11 // Method "<init>":(Ljava/lang/String;I)V 10: putstatic #12 // Field INSTANCE:Lcom/loadclass/test/Singleton; 13: iconst_1 14: anewarray #4 // class com/loadclass/test/Singleton 17: dup 18: iconst_0 19: getstatic #12 // Field INSTANCE:Lcom/loadclass/test/Singleton; 22: aastore 23: putstatic #1 // Field $VALUES:[Lcom/loadclass/test/Singleton; 26: return }
7: Double checked locking (DCL)
public class Singleton { // jdk1.6及之后,只要定义为private volatile static SingleTon instance 就可解决DCL失效问题。 // volatile确保instance每次均在主内存中读取,这样虽然会牺牲一点效率,但也无伤大雅。 // volatile可以保证即使java虚拟机对代码执行了指令重排序,也会保证它的正确性。 private volatile static Singleton singleton; private Singleton(){}; public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
DCL and Solution & Description:
To solve the problem of low performance caused by the synchronization implementation of delayed loading method, DCL, that is, double check lock method, can be used to avoid synchronization every time getInstance () method is called.
Double checked locking looks perfect. Unfortunately, according to the Java language specification, the above code is unreliable.
The two most important reasons for the above problems are as follows:
Sequence of problems
terms of settlement:
You can declare instance as volatile, that is, private volatile static singleton instance
After thread B reads a volatile variable, the values of all visible shared variables will become visible to thread B immediately before thread a writes the volatile variable.
Summary:
If singletons are loaded by different class loaders, there may be multiple instances of singleton classes. Assuming that it is not remote access, for example, some servlet containers use completely different class loaders for each servlet, so if two servlets access a singleton class, they will all have their own instances.
private static Class getClass(String classname) throws ClassNotFoundException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if (classLoader == null) { classLoader = Singleton.class.getClassLoader(); } return (classLoader.loadClass(classname)); }
If singleton implements Java io. Serializable interface, then the instance of this class may be serialized and restored. Anyway, if you serialize an object of a singleton class and then restore multiple objects, you will have multiple instances of a singleton class.
public class Singleton implements Serializable { public static Singleton INSTANCE = new Singleton(); private Singleton(){} //ObjectInputStream.readObject调用 private Object readResolve() { return INSTANCE; } }
summary
The above is my method of dealing with the real IP of the client. I hope the content of this article has a certain reference value for your study or work. Thank you for your support.