普通懒汉式
/**
* 懒汉式单例
*/
@Data
public class LazySingle implements Serializable {
private String singleName;
//volatile,确保本条指令不会因编译器的优化而省略,且要求每次直接读值
private static volatile LazySingle lazySingle=null;
//解决多线程不能保证单例情况 **Double Check(双重校验) + Lock(加锁)**
public static LazySingle getInstance() {
if(lazySingle==null){// 线程A和线程B同时看到singleton = null,如果不为null,则直接返回singleton
synchronized (LazySingle.class) {// 线程A或线程B获得该锁进行初始化
if(lazySingle == null){// 其中一个线程进入该分支,另外一个线程则不会进入该分支
lazySingle = new LazySingle();
}
}
}
return lazySingle;
}
使用序列化与反序列化破坏单例模式
try {
File file = new File("Singleton.txt");
//创建输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
//将单例对象写到文件中 序列化
oos.writeObject(LazySingle.getInstance());
//从文件读取单例对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
//反序列化得到对象lazySingle
LazySingle lazySingle=(LazySingle)ois.readObject();
System.out.println(lazySingle==LazySingle.getInstance()); //false
} catch (Exception e) {
e.printStackTrace();
}
原因
通过阅读源码发现,反序列化方法readObject()
的readObject0()
中如果是Object对象则调用readOrdinaryObject()
,该方法首先会通过一个三目运算来创建序列化的对象。如果这个对象能实例化就创建一个新对象
obj = desc.isInstantiable() ? desc.newInstance() : null;
解决方法
在通过三目运算创建了对象之后,还会去找这个对象里是否有readResolve()
方法,如果有,则通过这方法返回对象。
if (obj != null &&handles.lookupException(passHandle) == null && desc.hasReadResolveMethod()){
Object rep = desc.invokeReadResolve(obj);
}
所以只需要在单例类中新增readResolve()
方法即可
public Object readResolve() {
return getInstance();
}