单例模式失效问题

Scroll Down

单例模式失效问题

概要

最近学习设计模式时,单例模式的学习,有多种实现方式,但是总会遇到单例模式失效问题,在什么情况下会失效呢?如何解决?

失效方式

  • 反射
  • 序列化/反序列化

解决

/**
 * @author kong
 * @date 2021/09/12 16:02
 * blog: http://blog.kongyin.ltd
 */
public class ApiTest {

   /**
     * 破坏单例
     * 1.反射 2.序列和反序列化
     * 反射破坏单例模式
     */
    @Test
    public void test_destroy_singleton(){
        try {
            Class<?> clazz = Singleton_TEST_DES.class;
            // 获取私有方法
            Constructor<?> constructor = clazz.getDeclaredConstructor(null);
            // 因为要访问私有的构造方法,这里要设为true,相当于让你有权限去操作
            constructor.setAccessible(true);
            //暴力初始化
            Object o1 = constructor.newInstance();
            //调用了两次构造方法,相当于 new 了两次
            Object o2 = constructor.newInstance();
            //这里输出结果为false
            System.out.println(o1 == o2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 2.序列化
     */
    @Test
    public void test_destroy_singleton2(){
        Singleton_TEST_DES s1 = null;
        // 通过类本身获取对象
        Singleton_TEST_DES s2 = s1.getInstance();
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream("./SeriableSingleton.obj");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(s2);
            oos.flush();
            oos.close();
            // 从文件中反序列化为对象
            FileInputStream fis = new FileInputStream("./SeriableSingleton.obj");
            ObjectInputStream ois = new ObjectInputStream(fis);
            s1 = (Singleton_TEST_DES)ois.readObject();
            ois.close();
            // 对比结果,这里输出的结果为false
            System.out.println(s2 == s1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}
//使用静态内部类实现单例模式
class Singleton_TEST_DES implements Serializable {

    private static final long serialVersionUID = -4264591697494981165L;


    private static class SingletonHolder {
        private static Singleton_TEST_DES instance = new Singleton_TEST_DES();
    }
    // 私有的构造方法
    private Singleton_TEST_DES () {
        // 防止反射创建多个对象
        if(Singleton_TEST_DES.SingletonHolder.instance != null){
            throw new RuntimeException("不允许创建多个实例");
        }
    }

    public Singleton_TEST_DES getInstance () {
        return Singleton_TEST_DES.SingletonHolder.instance;
    }

    // 防止序列化创建多个对象,这个方法是关键
    private Object readResolve(){
        return Singleton_TEST_DES.SingletonHolder.instance;
    }


}