单例模式的核心目标是确保某个类在程序运行期间只存在一个实例,并且该实例可以被全局访问。在单线程环境下实现单例模式比较简单,但是在多线程并发场景中,如果没有做好同步控制,就可能出现多个线程同时创建实例的情况,导致单例失效。下面介绍几种Java中线程安全的单例模式实现方式。

饿汉式实现
饿汉式是最简单的线程安全单例实现方式,它在类加载阶段就完成实例的初始化,借助类加载机制保证线程安全,因为类加载过程是线程安全的。
public class HungrySingleton {
// 类加载时直接初始化实例
private static final HungrySingleton INSTANCE = new HungrySingleton();
// 私有构造方法,防止外部实例化
private HungrySingleton() {}
// 全局访问点
public static HungrySingleton getInstance() {
return INSTANCE;
}
}
这种方式的优点是实现简单,线程安全有保障,调用getInstance()方法时不需要同步,性能较好。缺点是如果实例的初始化比较耗费资源,而程序运行过程中一直没有调用getInstance()方法,就会造成资源浪费。
懒汉式加锁实现
懒汉式的思路是延迟实例的初始化,只有在第一次调用getInstance()方法时才创建实例,但是需要加锁保证线程安全。
public class LazyLockSingleton {
private static LazyLockSingleton instance;
private LazyLockSingleton() {}
// 方法加synchronized关键字保证同步
public static synchronized LazyLockSingleton getInstance() {
if (instance == null) {
instance = new LazyLockSingleton();
}
return instance;
}
}
这种方式的优点是实现了延迟加载,避免了资源浪费。缺点是getInstance()方法每次调用都需要加锁,在并发量高的场景下,同步锁会成为性能瓶颈,影响程序运行效率。
双重检查锁定实现
双重检查锁定是对懒汉式加锁实现的优化,只在实例未初始化时加锁,减少同步带来的性能开销。
public class DoubleCheckSingleton {
// 使用volatile关键字保证可见性和禁止指令重排
private static volatile DoubleCheckSingleton instance;
private DoubleCheckSingleton() {}
public static DoubleCheckSingleton getInstance() {
// 第一次检查,实例已存在则直接返回,无需加锁
if (instance == null) {
synchronized (DoubleCheckSingleton.class) {
// 第二次检查,防止多个线程同时通过第一次检查后重复创建实例
if (instance == null) {
instance = new DoubleCheckSingleton();
}
}
}
return instance;
}
}
这里需要注意instance变量必须加volatile修饰,因为instance = new DoubleCheckSingleton()这行代码在JVM中会被拆分为多个指令,可能出现指令重排的情况,导致其他线程拿到未初始化完成的实例。这种方式的优点是兼顾了延迟加载和性能,是常用的线程安全单例实现方式。
静态内部类实现
静态内部类实现利用了类加载机制的特性,外部类加载时不会加载内部类,只有调用getInstance()方法时才会加载内部类并初始化实例,同时保证线程安全。
public class InnerClassSingleton {
private InnerClassSingleton() {}
// 静态内部类,只有在被调用时才会加载
private static class SingletonHolder {
private static final InnerClassSingleton INSTANCE = new InnerClassSingleton();
}
public static InnerClassSingleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
这种方式的优点是实现了延迟加载,不需要加锁,性能较好,同时借助类加载机制保证了线程安全,实现也比较简洁,是比较推荐的单例实现方式。
枚举实现
枚举实现是《Effective Java》中推荐的单例实现方式,不仅能保证线程安全,还能防止反序列化重新创建新的对象。
public enum EnumSingleton {
INSTANCE;
// 可以添加自定义的方法
public void doSomething() {
System.out.println("执行单例实例的方法");
}
}
使用时直接通过EnumSingleton.INSTANCE获取实例即可。这种方式的优点是实现极其简单,天然支持序列化机制,不会因为反序列化产生新的实例,是目前最安全的单例实现方式。
不同实现方式对比
下面是几种线程安全单例实现方式的对比:
| 实现方式 | 是否线程安全 | 是否延迟加载 | 性能 | 防反序列化破坏 |
|---|---|---|---|---|
| 饿汉式 | 是 | 否 | 好 | 否 |
| 懒汉式加锁 | 是 | 是 | 差 | 否 |
| 双重检查锁定 | 是 | 是 | 好 | 否 |
| 静态内部类 | 是 | 是 | 好 | 否 |
| 枚举 | 是 | 否 | 好 | 是 |
开发者可以根据实际需求选择合适的实现方式,如果不需要考虑反序列化问题,静态内部类实现是比较好的选择;如果需要防止反序列化破坏单例,枚举实现是最优方案。
Java单例模式线程安全并发编程synchronized修改时间:2026-07-06 14:54:28