1.饿汉式(特点:调用效率高,不能延时加载)
//饿汉式 public 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; } }
时间: 2024-10-17 12:26:29