1. 饿汉式
// 饿汉式
public class Singleton {private static Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {return INSTANCE;}
}
2. 懒汉式
public class Singleton {
private static Singleton INSTANCE;
private Singleton() {}
public static Singleton getInstance() {if (INSTANCE == null) {INSTANCE = new Singleton();
}
return INSTANCE;
}
}
3. 线程平安懒汉式 - 双重查看
public class Singleton {
private static Singleton INSTANCE;
private Singleton() {}
public static Singleton getInstance() {if (INSTANCE == null) {synchronized(Singleton.class) {if (INSTANCE == null) {INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
4. 双重查看的不足之处
以下三种状况会毁坏双重查看的单例模式: 指令重排序、序列 / 反序列化、反射
4.1 指令重排序
INSTANCE = new Singleton()
语句并非原子操作,分为以下三步:
- 调配 Singleton 对象内存空间。
- 初始化对象。
- 将 INSTANCE 对象援用指向调配的内存空间。
因为指令重排序的问题,以上指令在理论状况可能以 1 -> 3 -> 2 的程序执行。
在多线程的状况下可能呈现:
执行程序 | 线程 A | 线程 B |
---|---|---|
1 | 调配 Singleton 对象内存空间 | |
2 | 将 INSTANCE 对象援用指向调配的内存空间 | |
3 | 拜访 getInstance() 办法,判断 INSTANCE 对象是否为 null | |
4 | 因为 INSTANCE 曾经实现了对象援用指向,因为不为 null,但此时 INSTANCE 还没有实现初始化 | |
5 | 初始化对象 | |
6 | 拜访 INSTANCE 援用的对象 |
解决办法:
应用 volatile 润饰 INSTANCE 对象
public class Singleton {
private volatile static Singleton INSTANCE;
private Singleton() {}
public static Singleton getInstance() {if (INSTANCE == null) {synchronized(Singleton.class) {if (INSTANCE == null) {INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
4.2 序列 / 反序列化毁坏单例
参考大佬文章:https://segmentfault.com/a/11…
如果想要避免单例被序列 / 反序列化毁坏。就让单例类实现 readResolve() 办法。
public class Singleton {
private volatile static Singleton INSTANCE;
private Singleton() {}
public static Singleton getInstance() {if (INSTANCE == null) {synchronized(Singleton.class) {if (INSTANCE == null) {INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
private Object readResolve() {return Singleton.INSTANCE;}
}
4.3 反射毁坏单例
参考大佬文章:https://segmentfault.com/a/11…
为了避免反射毁坏单例,采纳枚举实现单例模式。
public enum EnumSingleton {
INSTANCE;
public EnumSingleton getInstance(){return INSTANCE;}
}
参考文献
https://www.liaoxuefeng.com/w…
https://segmentfault.com/a/11…