写在前面
单例设计模式,相信是大家接触设计模式时的入门设计模式,它理解起来比较简单,当然实现起来也很简单,但是别看不上这简单的东西,简单的事情重复做将不再简单,再复杂的事情拆分开来也是由很多简单的事情的集合。接下来来过一遍三种经典的单例模式。
单例模式三个主要特点:
- 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
如果有哪些不对的地方烦请指认,先行感谢