单例模式有哪几种实现?如何保证线程安全?
重点
单例模式常见的有: 饿汉式、懒汉式(线程安全版需要加双重检查锁定)、静态内部类、枚举单例(Java特有)等几个实现方式。
- 饿汉式:实例在类加载时就创建,线程安全,但如果实例初始化比较重或没有被使用会浪费资源
- 懒汉式:实例在首次访问时创建,节约资源,但需要保证线程安全
- 双重检查锁定:在懒汉式的基础上优化,直接加锁效率太低,双重检查锁只在第一次检查实例为空时加锁,提高性能。
- 静态内部类:利用类加载机制实现懒加载和线程安全,推荐使用
- 枚举单例(Java特有):通过枚举类实现,简单且防止反射和序列化攻击。
扩展
为什么需要双重检查锁定?
因为懒汉式单例在多线程环境下,可能出现多个线程同时初始化实例的问题,最简单是加个锁:
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
但是这样一来,每次调用getInstance方法都需要加锁,而实际上只需要在第一次创建示例时加锁。在高并发环境下,频繁获取单例对象的锁的操作会显著降低性能。
而双重检查锁定通过减少加锁的范围,避免了每次获取实例时都枷锁的问题,提高了性能。
public class Singleton {
private static volatile Singleton instance; // 使用 volatile 防止指令重排
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // 第一次检查:避免不必要的同步
synchronized (Singleton.class) {
if (instance == null) { // 第二次检查:确保实例唯一
instance = new Singleton();
}
}
}
return instance;
}
}
为什么双重检查锁定需要volatile关键字?
在Java中,volatile修饰符用于防止指令冲排序,从而确保双重检查锁定的正确性。
instance = new Signleton是一个非原子操作,它分为以下三步:
- 分配内存空间。
- 初始化对象。
- 将对象引用赋值给
instance。
在没有volatile的情况下,编译器和CPU可能会对这些步骤进行冲排序(比如执行顺序边哼1->3->2)。此时,另一个线程可能会在instance被赋值后,但对象尚未完成初始化时访问它,从而导致错误。
所以将instance声明为volatile,可以禁止指令重排序,确保对象的初始化过程对所有线程可见。
private static volatile Singleton instance;
保证instance的写操作对其他线程立即可见,并禁止重排序优化,确保双重检查锁定的正确性。
总结:
- 双重检查锁定通过缩小加锁范围,仅在必要时同步代码块,既保证线程安全,又提升性能。
volatile关键字是实现双重检查锁的关键,防止指令冲排序导致未初始化对象被访问。
Java 单例实现代码示例
饿汉式(线程安全,类加载时初始化):
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
懒汉式(线程不安全,需改进):
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
双重检查锁定(线程安全,推荐):
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
静态内部类(线程安全,推荐):
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
枚举单例:
public enum Singleton {
INSTANCE;
public void bizMethod() {
// 一些业务逻辑方法
}
}
//使用
Singleton singleton = Singleton.INSTANCE;
singleton.bizMethod();

浙公网安备 33010602011771号