1.餓漢式(特色:調用效率高,不能延時加載)java
//餓漢式 public class SingletonDemo1 { private static SingletonDemo1 instance = new SingletonDemo1(); private SingletonDemo1(){} public static SingletonDemo1 getInstance(){ return instance; } }
2.懶漢式(特色:可延時加載,調用效率低)
//懶漢式 public class SingletonDemo2{ private static SingletonDemo2 instance; private SingletonDemo2(){} public static synchronized SingletonDemo2 getInstance(){ if(instance==null){ instance = new SingletonDemo2(); } return instance; } }
3.雙重檢測式(因爲JVM底層緣由,不可靠,避免使用)
//雙重檢測鎖 public class SingletonDemo3{ private static SingletonDemo3 instance; private SingletonDemo3(){} public static SingletonDemo3 getInstance(){ if(instance==null){ synchronized(SingletonDemo3.class){ if(instance==null){ instance = new SingletonDemo3(); } } } return instance; } }
4.靜態內部類式(特色:調用效率高且能夠延時加載)
//靜態內部類實現方式 public class SingletonDemo4{ private static class SingletonClassInstance{ private static final SingletonDemo4 instance = new SingletonDemo4(); } private SingletonDemo4(){} public static SingletonDemo4 getInstance(){ return SingletonClassInstance.instance; } }
5.枚舉式(特色:調用效率高,不能延時加載,自然防止反射和反序列化漏洞)
//枚舉式 public enum SingletonDemo5{ INSTANCE; public void SingletonOperation(){ } }對於1--4,可利用反射和反序列化破解單列,以餓漢式爲例
package cn.baokx.gof23; import java.lang.reflect.Constructor; public class Test { public static void main(String[] args) throws Exception { //利用反射破解單例 Class<SingletonDemo1> clazz = (Class<SingletonDemo1>)Class.forName("cn.baokx.gof23.SingletonDemo1"); Constructor<SingletonDemo1> c = clazz.getDeclaredConstructor(null); c.setAccessible(true); SingletonDemo1 s1 = c.newInstance(); SingletonDemo1 s2 = c.newInstance(); System.out.println(s1==s2); } }
解決方案:
//餓漢式 public class SingletonDemo1 { private static SingletonDemo1 instance = new SingletonDemo1(); private SingletonDemo1(){ if(null!=instance){ throw new RuntimeException(); } } public static SingletonDemo1 getInstance(){ return instance; } }
package cn.baokx.gof23; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class Test { public static void main(String[] args) throws Exception { //利用序列化破解單例 SingletonDemo1 s1 = SingletonDemo1.getInstance(); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/obj.data")); oos.writeObject(s1); oos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/obj.data")); SingletonDemo1 s2 = (SingletonDemo1)ois.readObject(); ois.close(); System.out.println(s1==s2); } }
解決方案:
//餓漢式 public class SingletonDemo1 implements Serializable{ private static SingletonDemo1 instance = new SingletonDemo1(); //防反射破解單例 private SingletonDemo1(){ if(null!=instance){ throw new RuntimeException(); } } public static SingletonDemo1 getInstance(){ return instance; } //防反序列化破解單例 private Object readResolve() throws ObjectStreamException { return instance; } }