关于java:单例设计模式记录

1次阅读

共计 6315 个字符,预计需要花费 16 分钟才能阅读完成。

写在后面

单例设计模式,置信是大家接触设计模式时的入门设计模式,它了解起来比较简单,当然实现起来也很简略,然而别看不上这简略的货色,简略的事件反复做将不再简略,再简单的事件拆分开来也是由很多简略的事件的汇合。接下来来过一遍三种经典的单例模式。

单例模式三个次要特点:

  • 1、构造方法私有化;
  • 2、实例化的变量援用私有化;
  • 3、获取实例的办法共有。

1、双重否定单例模式

public class DCLSingleton implements Serializable {
    private static final long serialVersionUID = 6242241249985894658L;
    /**
     * volatile:内存中可见 和 避免指令重排
     * 这里次要作用是避免指令重排
     */
    private volatile static DCLSingleton instance;
    
    private DCLSingleton() {}
    
    public static DCLSingleton getInstance() {if (instance == null) {synchronized (DCLSingleton.class) {if (instance == null) {instance = new DCLSingleton();
                }
            }
        }
        return instance;
    }
    public void singletonFunction() {System.out.println("DCLSingleton test.");
    }
}

2、注销式 / 动态外部类单例模式

public class StaticSingleton implements Serializable {
    private static final long serialVersionUID = 5537012394799626447L;

    private static class SingletonHolder {private static final StaticSingleton INSTANCE = new StaticSingleton();
    }
    private StaticSingleton(){}
    public static final StaticSingleton getInstance() {return SingletonHolder.INSTANCE;}
    public void singletonFunction() {System.out.println("StaticSingleton test.");
    }
}

3、枚举单例模式

public enum SingletonEnum {
    /**
     * 实例
     */
    INSTANCE;

    /**
     * 办法
     */
    public void singletonFunction() {System.out.println("SingletonEnum test.");
    }
}

测试

以单例性和安全性 2 个方向对以上 3 种单例模式进行测试,看哪种比拟适宜

1、序列化和反序列化测试单例性

public class TestSerializable {public static void main(String[] args) throws IOException, ClassNotFoundException {System.out.println("---------------- 双重否定单例模式测试开始 -----------------------------");
        DCLSingleton instance_1 = DCLSingleton.getInstance();
        ByteArrayOutputStream byteArrayOutputStream_1 = new ByteArrayOutputStream();
        new ObjectOutputStream(byteArrayOutputStream_1).writeObject(instance_1);

        ObjectInputStream objectInputStream_1 = new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream_1.toByteArray()));
        DCLSingleton singleton_1 = (DCLSingleton) objectInputStream_1.readObject();

        //com.songo.singletonpattern.service.SingletonPattern1@27c170f0
        System.out.println(instance_1);
        //com.songo.singletonpattern.service.SingletonPattern1@3d494fbf
        System.out.println(singleton_1);
        //DCLSingleton test.
        singleton_1.singletonFunction();
        // 序列化和反序列化后是否雷同:false
        System.out.println("序列化和反序列化后是否雷同:" + (instance_1 == singleton_1));
        System.out.println("---------------- 双重否定单例模式测试完结 -----------------------------");

        System.out.println("---------------- 动态外部类单例模式测试开始 ---------------------------");
        StaticSingleton instance_2 = StaticSingleton.getInstance();
        ByteArrayOutputStream byteArrayOutputStream_2 = new ByteArrayOutputStream();
        new ObjectOutputStream(byteArrayOutputStream_2).writeObject(instance_2);

        ObjectInputStream objectInputStream_2 = new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream_2.toByteArray()));
        StaticSingleton singleton_2 = (StaticSingleton) objectInputStream_2.readObject();

        //com.songo.singletonpattern.service.StaticSingleton@7cd84586
        System.out.println(instance_2);
        //com.songo.singletonpattern.service.StaticSingleton@30dae81
        System.out.println(singleton_2);
        //StaticSingleton test.
        singleton_2.singletonFunction();
        // 序列化和反序列化后是否雷同:false
        System.out.println("序列化和反序列化后是否雷同:" + (instance_2==singleton_2));
        System.out.println("---------------- 动态外部类单例模式测试完结 ---------------------------");

        System.out.println("---------------- 枚举单例模式测试完结 ---------------------------------");
        SingletonEnum instance_3 = SingletonEnum.INSTANCE;
        ByteArrayOutputStream byteArrayOutputStream_3 = new ByteArrayOutputStream();
        new ObjectOutputStream(byteArrayOutputStream_3).writeObject(instance_3);

        ObjectInputStream objectInputStream_3 = new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream_3.toByteArray()));
        SingletonEnum singleton_3 = (SingletonEnum) objectInputStream_3.readObject();

        //INSTANCE
        System.out.println(instance_3);
        //INSTANCE
        System.out.println(singleton_3);
        //SingletonEnum test.
        singleton_3.singletonFunction();
        // 序列化和反序列化后是否雷同:true
        System.out.println("序列化和反序列化后是否雷同:" + (instance_3==singleton_3));
        System.out.println("---------------- 枚举单例模式测试完结 ---------------------------------");

    }
}

由程序后果可知枚举单例模式通过序列化和反序列化操作后对象没有扭转,单例性够强,此处枚举单例模式完胜

2、通过反射测试安全性

public class Testreflect {public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {System.out.println("---------------- 双重否定单例模式测试开始 -----------------------------");
        DCLSingleton instance_1 = DCLSingleton.getInstance();
        Constructor constructor_1 = DCLSingleton.class.getDeclaredConstructor();
        constructor_1.setAccessible(true);
        DCLSingleton newInstance_1 = (DCLSingleton) constructor_1.newInstance();

        //com.songo.singletonpattern.service.SingletonPattern1@4d7e1886
        System.out.println(instance_1);
        //com.songo.singletonpattern.service.SingletonPattern1@3cd1a2f1
        System.out.println(newInstance_1);
        //DCLSingleton test.
        newInstance_1.singletonFunction();
        // 通过反射失去的对象和原来是否雷同:false
        System.out.println("通过反射失去的对象和原来是否雷同:" + (instance_1 == newInstance_1));
        System.out.println("---------------- 双重否定单例模式测试完结 -----------------------------");

        System.out.println("---------------- 动态外部类单例模式测试开始 ---------------------------");
        StaticSingleton instance_2 = StaticSingleton.getInstance();
        Constructor constructor_2 = StaticSingleton.class.getDeclaredConstructor();
        constructor_2.setAccessible(true);
        StaticSingleton newInstance_2 = (StaticSingleton) constructor_2.newInstance();

        //com.songo.singletonpattern.service.SingletonPattern2@2f0e140b
        System.out.println(instance_2);
        //com.songo.singletonpattern.service.SingletonPattern2@7440e464
        System.out.println(newInstance_2);
        //StaticSingleton test.
        newInstance_2.singletonFunction();
        // 通过反射失去的对象和原来是否雷同:false
        System.out.println("通过反射失去的对象和原来是否雷同:" + (instance_2 == newInstance_2));
        System.out.println("---------------- 动态外部类单例模式测试完结 ---------------------------");

        System.out.println("---------------- 枚举单例模式测试开始 ---------------------------------");
        // 枚举没有无参构造方法,这里加上参数
        SingletonEnum instance_3 = SingletonEnum.INSTANCE;
        Constructor constructor_3 = SingletonEnum.class.getDeclaredConstructor(String.class,int.class);
        constructor_3.setAccessible(true);
        // 异样 Cannot reflectively create enum objects
        SingletonEnum newInstance_3 = (SingletonEnum) constructor_3.newInstance("test",111);

        System.out.println(instance_3);
        System.out.println(newInstance_3);
        newInstance_3.singletonFunction();
        System.out.println(instance_3 == newInstance_3);
        System.out.println("---------------- 枚举单例模式测试完结 ---------------------------------");
    }

由程序后果可知枚举单例模式没有无参的构造方法,即便结构有参的构造方法反射也不通过,报异样 Cannot reflectively create enum objects,安全性够强,此处枚举单例模式完胜

代码详情可参考源码,github:https://github.com/charmsongo/songo-code-samples/tree/master/singleton-pattern

如果有哪些不对的中央烦请指认,后行感激

正文完
 0