单例模式

Suffocat1ng

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()语句并非原子操作,分为以下三步:

  1. 分配Singleton对象内存空间。
  2. 初始化对象。
  3. 将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...
阅读 274
1 声望
0 粉丝
0 条评论
1 声望
0 粉丝
文章目录
宣传栏