Implementation of singleton mode (5 types)
Commonly used:
Hungry style (thread safe, high call efficiency, but cannot be loaded in a delayed manner)
Lazy style (thread safe, low call efficiency, can be loaded in delay)
other:
Double detection lock type (due to the underlying internal model of jvm, there will be problems occasionally and will not be built and used)
Static internal class (thread-safe, high call efficiency, but can be loaded in a delayed manner)
Enumerate singletons (thread-safe, high call efficiency, and cannot be loaded in delay)
The specific code of the singleton of Hungry Man is as follows:
package com.lcx.mode; /** * * A singleton of hungry people. Regardless of whether this object is used in the future or not, we create an instance of this object from the beginning. * When needed, we return the created instance object, so we are relatively hungry, so this is called a singleton of hungry people. * @author qq1013985957 * */ public class SingletonHanger { private static final SingletonHanger instance = new SingletonHanger(); private SingletonHanger() { } public static SingletonHanger getInstance(){ return instance; } } /** * Lazy Han-style singleton, when a singleton object is needed, it will create the only singleton object, and call it again later, and the returned singleton object is also the first created singleton object* Initializes the static member to null, and creates it when a singleton is obtained, so it is called lazy Han-style. * @author qq1013985957 * */ class SingletonLazy{ private static SingletonLazy instance = null; private SingletonLazy() { } /** * The singleton implemented by this method cannot be used in multiple threads. Multiple lines can enter the if method at the same time, which will cause multiple singleton objects to be generated. * @return */ public static SingletonLazy getInstance1(){ if(instance==null){ instance = new SingletonLazy(); } return instance; } /** * Everyone will think of synchronization. The synchronous method can implement multi-threaded singleton* However, this method is not desirable and seriously affects performance. Because the method must be checked every time you get a singleton, you can only use the synchronized code block to achieve synchronization. * @return */ public static synchronized SingletonLazy getInstance2(){ if(instance==null){ instance = new SingletonLazy(); } return instance; } /** * Use the synchronized code block to use the synchronized code block in the if method to determine whether a singleton exists, and check again in the synchronized code block whether the singleton has been generated. * This is the method of double checking locking on the Internet* @return */ public static synchronized SingletonLazy getInstance3(){ if(instance==null){ synchronized (SingletonLazy.class) { if(instance==null){ instance = new SingletonLazy(); } } } return instance; } } /** * Use enumerations to implement singleton mode, which is also the recommended way to use in Effective Java* Instantiation according to the specific situation. For students who are not familiar with enums, you can refer to the preliminary understanding of my blog JAVA enumeration class. * Its benefits: It is more concise and provides a serialization mechanism for free, absolutely preventing multiple instantiation, even in the face of complex sequence and reflection attacks. * @author qq1013985957 * */ enum SingletionEnum{ SingletionEnum("Singleton Enum"); private String str ; private SingletionEnum(String str){ this.setStr(str); } public String getStr() { return str; } public void setStr(String str) { this.str = str; } } The above singleton pattern is not tested. You can test it to determine whether the hashcode of the object is consistent to determine whether it is the same object.
The evil and lazy methods cannot prevent reflection from implementing multiple instances. Through reflection, setting the ACcessible.setAccessible method can call the private constructor. You can modify the constructor to throw an exception when it is asked to create a second instance.
In fact, this cannot guarantee a singleton. After serialization, deserialization can create a new instance, and add readResolve() method to the singleton class to prevent it.
The lazy man-style singleton code is as follows:
package com.lcx.mode; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; /** * Lazy Man-style singletons are created when a singleton object is needed. When a singleton object is needed, it will be called again later. The returned singleton object is also the first created singleton object* Initializes the static member to null, and creates it when a singleton is obtained, so it is called lazy Man-style. * @author qq1013985957 * */ public class Singleton implements Serializable{ /** * */ private static final long serialVersionUID = -5271537207137321645L; private static Singleton instance = null; private static int i = 1; private Singleton() { /** * Prevent reflection attacks, only run and call the constructor once, throw exception the second time*/ if(i==1){ i++; }else{ throw new RuntimeException("Constructor can only be called once"); } System.out.println("Call Singleton's private constructor"); } /** * Use the synchronized code block to use the synchronized code block in the if method to determine whether a singleton exists, and check again in the synchronized code block whether the singleton has been generated. * This is what the Internet calls the double check locking method* @return */ public static synchronized Singleton getInstance(){ if(instance==null){ synchronized (Singleton.class) { if(instance==null){ instance = new Singleton(); } } return instance; } /** * Prevent desequence from generating new singleton objects. This is what is said in the book Effective Java. This method can be prevented. I don’t understand the specific details* @return */ private Object readResolve(){ return instance; } public static void main(String[] args) throws Exception { test1(); test2(); } /** * Testing desequence is still singleton mode* @throws Exception */ public static void test2() throws Exception{ Singleton s = Singleton.getInstance(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(new File("E://Singleton.txt"))); objectOutputStream.writeObject(s); ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(new File("E://Singleton.txt")))); Object readObject = objectInputStream.readObject(); Singleton s1 = (Singleton)readObject; System.out.println("s.hashCode():"+s.hashCode()+",s1.hashCode():"+s1.hashCode()); objectOutputStream.flush(); objectOutputStream.close(); objectInputStream.close(); objectInputStream.close(); } /** * Test reflection attack* @throws Exception */ public static void test1(){ Singleton s = Singleton.getInstance(); Class c = Singleton.class; Constructor privateConstructor; try { privateConstructor = c.getDeclaredConstructor(); privateConstructor.setAccessible(true); privateConstructor.newInstance(); } catch (Exception e) { e.printStackTrace(); } } }Verify the reflection attack results:
If the result of the readResolve method is not added:
The result of adding readResolve method:
Thank you for reading, I hope it can help you. Thank you for your support for this site!