提纲
- 饿汉模式
- 懒汉模式(线程不安全)
- 懒汉模式(线程安全)
- 双重检验模式
- 静态内部类单例模式
- 枚举模式
- 反序列化导致重新创建对象
1. 饿汉模式
- 类加载时就完成了实例化,避免多线程的同步问题,但是没有达到懒加载效果
- 从始至终未使用过这个实例,会造成内存的浪费
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
private 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. 懒汉模式(线程安全)
用于多线程,每次调用getInstance都需要进行同步,但是会造成同步开销
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
4. 双重检验模式(DSL)
- 第一次为了不必要的同步操作,第二次在singleton等于null才去创建实例,资源利用率高
- 使用volatile 会造成性能的影响
- 高并发的情况下会有缺陷,DSL会失效,建议静态内部类单例来替代DCL
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;
}
}
5. 静态内部类单例模式
第一次加载Singleton类时并不会初始化,只有第一次加载SingletonHolder.sInstance方法时虚拟机才会加载SingletonHodler并初始化,既能保障线程安全,又能保证Singleton类的唯一性
public class Singleton {
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.sInstance;
}
private static class SingletonHolder {
private static final Singleton sInstance = new Singleton();
}
}
6.枚举单例
枚举单例的创建是线程安全的,并在任何情况下都是单例的
enum Singleton {
SINGLETON;
public void doSomething() {
}
}
7.反序列化问题
反序列化操作提供readResolve方法,这个方法可以控制对象的反序列化
- 不能有参数 2. 返回要为Object类型的方法 3. 返回的值是单例实例的引用
在ObjectStraeamClass源码中,那怕有没有readResolve方法都会创建这个对象,只是将内存中指向的地址重新赋值到待返回的引用上
class Singleton implements Serializable {
private Object readResolve() throws ObjectStreamException {
return instance;
}
}