單例模式的基本要素html
/** * 餓漢式 * 一開始就new好了 */ public class HungrySingleton implements Serializable { /** * 能夠直接new也能夠適用靜態塊中建立 * */ private final static HungrySingleton hungrySingleton; static { hungrySingleton = new HungrySingleton1(); } public static HungrySingleton getInstance() { return hungrySingleton; } /** * 私有構造函數 */ private HungrySingleton() {} }
/** * 懶漢式 * 線程不安全 */ public class LazySingleton { private static LazySingleton lazySingleton = null; //線程不安全,當有兩個線程同時建立對象,會違背單例模式 public static LazySingleton getInstance() { if (lazySingleton == null) { //會發生指令重排 lazySingleton = new LazySingleton(); } return lazySingleton; } private LazySingleton() {} }
/** * 懶漢式 * 線程不安全 */ public class LazyDoubleCheckSingleton { //volatile 禁止指令重排序 private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null; /** * 在靜態方法中直接加synchronized至關於鎖了類 * @return */ public static LazyDoubleCheckSingleton getInstance() { //一樣實鎖類, 指令重排序 if (lazyDoubleCheckSingleton == null) { synchronized (LazyDoubleCheckSingleton.class) { if (lazyDoubleCheckSingleton == null) { /** * 1.分配內存給這個對象 * 2.初始化對象 * 3.設置lazyDoubleCheckSingleton指向剛分配的內存 * 2 3 順序有可能發生顛倒 * intra-thread semantics 不會改變單線程執行結果,指令重排序 */ lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton(); } } } return lazyDoubleCheckSingleton; } private LazyDoubleCheckSingleton() {} }
public class StaticInnerClassSingleton { /** * 看靜態類的初始化鎖那個線程能夠拿到 */ private static class InnerClass { private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton(); } public static StaticInnerClassSingleton getInstance() { return InnerClass.staticInnerClassSingleton; } private StaticInnerClassSingleton () { if (InnerClass.staticInnerClassSingleton != null) { throw new RuntimeException("單例對象禁止反射調用"); } } }
public class ContainerSingleton { //靜態容器, 注意map不是線程安全的,若是爲了線程安全可使用HashTable或者ConcurrentHashMap private static Map<String, Object> singletonMap = new HashMap<>(); public static void putInstance (String key, Object instance) { if (key != null && key.length() != 0) { if (!singletonMap.containsKey(key)) { singletonMap.put(key, instance); } } } public static Object getInstance (String key) { return singletonMap.get(key); } }
public enum EnumInstance { /** * 具體的單例實例 */ INSTANCE { protected void printTest () { System.out.println("K.O print Test!"); } }; private Object data; protected abstract void printTest(); public Object getData() { return data; } public void setData(Object data) { this.data = data; } public static EnumInstance getInstance() { return INSTANCE; } }
/** * 線程級單例模式 */ public class ThreadLocalInstance { //靜態的ThreadLocal類保存對象 private static final ThreadLocal<ThreadLocalInstance> threadLocal = ThreadLocal.withInitial(ThreadLocalInstance::new); private ThreadLocalInstance () {} public static ThreadLocalInstance getInstance () { return threadLocal.get(); } }
public class SerializableTest { public static void main(String[] args) throws IOException, ClassNotFoundException { //1.實例化 HungrySingleton instance = HungrySingleton.getInstance(); //2.寫入本地文件 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file")); oos.writeObject(instance); //3.讀取 File file = new File("singleton_file"); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); HungrySingleton newInstance = (HungrySingleton) ois.readObject(); //4.比較 System.out.println(instance); System.out.println(newInstance); System.out.println(instance == newInstance); } }
org.ko.singleton.hungry.HungrySingleton@135fbaa4 org.ko.singleton.hungry.HungrySingleton@568db2f2 false
/** * 餓漢式 * 一開始就new好了 */ public class HungrySingleton implements Serializable { private final static HungrySingleton hungrySingleton; static { hungrySingleton = new HungrySingleton(); } public static HungrySingleton getInstance() { return hungrySingleton; } /** * 寫完後,序列化對象會經過反射調用這個方法 * 徹底是ObjectInputStream寫死的,並無任何繼承關係 * 其實每次序列化 反序列化 都已經建立對象了,只是最後返回的這一個 * @return */ private Object readResolve () { return hungrySingleton; } private HungrySingleton() {} }
org.ko.singleton.hungry.HungrySingleton@135fbaa4 org.ko.singleton.hungry.HungrySingleton@135fbaa4 true
爲何添加了readResolve()方法就能夠了?java
/** * 類加載時就已經建立好對象 */ public class ReflectTest { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class objectClass = HungrySingleton.class; Constructor constructor = objectClass.getDeclaredConstructor(); constructor.setAccessible(true); //反射建立 HungrySingleton instance = HungrySingleton.getInstance(); //正常建立 HungrySingleton newInstance = (HungrySingleton) constructor.newInstance(); System.out.println(instance); System.out.println(newInstance); System.out.println(instance == newInstance); //StaticInnerClassSingleton類也是同樣的 } }
org.ko.singleton.hungry.HungrySingleton@1540e19d org.ko.singleton.hungry.HungrySingleton@677327b6 false
/** * 餓漢式 * 一開始就new好了 */ public class HungrySingleton implements Serializable { private final static HungrySingleton hungrySingleton; static { hungrySingleton = new HungrySingleton(); } public static HungrySingleton getInstance() { return hungrySingleton; } /** * 寫完後,序列化對象會經過反射調用這個方法 * 徹底是ObjectInputStream寫死的,並無任何繼承關係 * 其實每次序列化 反序列化 都已經建立對象了,只是最後返回的這一個 * @return */ private Object readResolve () { return hungrySingleton; } private HungrySingleton() { /** * 對一開始就建立好了的類有效 */ if (hungrySingleton != null) { throw new RuntimeException("單例對象禁止反射調用"); } } }
Exception in thread "main" java.lang.reflect.InvocationTargetException at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at org.ko.singleton.ReflectTest1.main(ReflectTest1.java:23) Caused by: java.lang.RuntimeException: 單例對象禁止反射調用 at org.ko.singleton.hungry.HungrySingleton2.<init>(HungrySingleton2.java:36) ... 5 more
/** * 枚舉類測試 */ public class SerializableTest { public static void main(String[] args) throws IOException, ClassNotFoundException { //測試枚舉類型 EnumInstance instance = EnumInstance.getInstance(); //設置對象 instance.setData(new Object()); //寫入文件 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file")); oos.writeObject(instance); //讀取文件 File file = new File("singleton_file"); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); EnumInstance newInstance = (EnumInstance) ois.readObject(); //比較實例 System.out.println(instance); System.out.println(newInstance); System.out.println(instance == newInstance); //比較實例中引用對象 System.out.println(instance.getData()); System.out.println(newInstance.getData()); System.out.println(instance.getData() == newInstance.getData()); } }
INSTANCE INSTANCE true java.lang.Object@5fd0d5ae java.lang.Object@5fd0d5ae true
/** * 類加載時就已經建立好對象 */ public class ReflectTest { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class objectClass = EnumInstance.class; Constructor constructor = objectClass.getDeclaredConstructor(String.class, int.class); constructor.setAccessible(true); //反射對象 EnumInstance newInstance = (EnumInstance) constructor.newInstance("K.O", 1); //實例對象 EnumInstance instance = EnumInstance.getInstance(); System.out.println(instance); System.out.println(newInstance); System.out.println(instance == newInstance); } }
Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects at java.lang.reflect.Constructor.newInstance(Constructor.java:417) at org.ko.singleton.ReflectTest3.main(ReflectTest3.java:21)
//final的 public final class EnumInstance extends Enum{ public static EnumInstance[] values(){ return (EnumInstance[])$VALUES.clone(); } public static EnumInstance valueOf(String name){ return (EnumInstance)Enum.valueOf(org/ko/singleton/byenum/EnumInstance, name); } //私有構造器 private EnumInstance(String s, int i){ super(s, i); } public Object getData(){ return data; } public void setData(Object data){ this.data = data; } public static EnumInstance getInstance(){ return INSTANCE; } //static final public static final EnumInstance INSTANCE; private Object data; private static final EnumInstance $VALUES[]; //經過靜態塊加載它,比較像餓漢模式 static { INSTANCE = new EnumInstance("INSTANCE", 0); $VALUES = (new EnumInstance[] { INSTANCE }); } }
單例模式
:https://github.com/sigmako/design-pattern/tree/master/singletongit
慕課網設計模式精講
: https://coding.imooc.com/class/270.html 23種設計模式(1):單例模式
: https://blog.csdn.net/zhengzhb/article/details/7331369