单例模式有哪几种实现?如何保证线程安全?

重点

单例模式常见的有: 饿汉式、懒汉式(线程安全版需要加双重检查锁定)、静态内部类、枚举单例(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是一个非原子操作,它分为以下三步:

  1. 分配内存空间。
  2. 初始化对象。
  3. 将对象引用赋值给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();

posted @ 2026-04-21 09:34  生活的样子就该是那样  阅读(7)  评论(0)    收藏  举报