除了枚举单列模式外,其余的单例实现方式都有可能被反射和反序列化所破坏。那么如何解决反射和反序列化对单例模式的破坏呢?
1、反射方式破解单例的解决方法:这种方式比较好理解。当通过反射方式调用构造方法进行创建创建时,直接抛异常。不运行此中操 作。
/**
* @author atao
* @version 1.0.0
* @ClassName Demo7.java
* @Description 懒汉式-方式3(双重检查锁)双重检查锁模式是一种非常好的单例实现模式,解决了单例、性能、线程安全问题,上面的双重检
* 测锁模式看上去完美无缺,其实是存在问题,在多线程的情况下,可能会出现空指针问题,出现问
* 题的原因是JVM在实例化对象的时候会进行优化和指令重排序操作。
* 要解决双重检查锁模式带来空指针异常的问题,只需要使用 volatile 关键字, volatile 关
* 键字可以保证可见性和有序性。
* @createTime 2022年03月05日 10:35:00
*/
public class Demo7 {
private static volatile Demo7 singleton;
private Demo7(){
// 解决反射对单例模式的破坏
if (singleton != null){
throw new RuntimeException();
}
}
public static Demo7 getInstance(){
if (singleton == null){
synchronized (Demo2.class){
if (singleton == null){
singleton = new Demo7();
}
}
}
return singleton;
}
}
2、在Singleton类中添加 readResolve() 方法,在反序列化时被反射调用,如果定义了这个方法, 就返回这个方法的值,如果没有定义,则返回新new出来的对象。
/**
* @author atao
* @version 1.0.0
* @ClassName Demo8.java
* @Description 懒汉式-方式4(静态内部类方式)静态内部类单例模式中实例由内部类创建,由于 JVM 在加载外部类的过程中, 是不会加载静态
* 内部类的, 只有内部类的属性/方法被调用时才会被加载, 并初始化其静态属性。静态属性由于被
* static 修饰,保证只被实例化一次,并且严格保证实例化顺序。
* @createTime 2022年03月05日 10:37:00
*/
public class Demo8 {
private Demo8 singleton;
private Demo8(){
}
private static class inner{
public static Demo8 singleton = new Demo8();
}
public static Demo8 getInstance(){
return Demo8.inner.singleton;
}
/**
* 解决反序列化对单例模式的破坏
* @return
*/
private Object readResolve(){
return Demo8.inner.singleton;
}
}