Skip to content

除了枚举单列模式外,其余的单例实现方式都有可能被反射和反序列化所破坏。那么如何解决反射和反序列化对单例模式的破坏呢?

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;
    }


}

Released under the MIT License.