Java中常用的线程安全单例模式实现
1. 饿汉式(线程安全,类加载时初始化)
特点:简单且线程安全,但如果实例过于占用资源且程序可能不使用它,会造成内存浪费。
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
// 私有构造方法,防止外部创建实例
private Singleton() {}
// 全局访问点
public static Singleton getInstance() {
return INSTANCE;
}
}
-
优点:实现简单,类加载时就完成实例化,线程安全。
-
缺点:即使不使用也会实例化,占用资源。
2. 懒汉式(线程不安全,延迟加载)
特点:实例在需要时创建,但默认实现线程不安全。
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
// 私有构造方法,防止外部创建实例
private Singleton() {}
// 全局访问点
public static Singleton getInstance() {
return INSTANCE;
}
}
-
缺点:在多线程环境中可能会创建多个实例,不推荐在并发场景下使用。
3. 懒汉式 + synchronized(线程安全,但性能较差)
特点:通过 synchronized 关键字确保线程安全,但性能较低。
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
-
优点:线程安全,延迟加载。
-
缺点:
synchronized会影响性能,每次调用都要获取锁。
4. 双重检查锁(推荐,性能较高)
特点:结合延迟加载与线程安全,减少同步开销。
public class Singleton {
// 使用 volatile 确保多线程下的可见性和禁止指令重排序
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;
}
}
-
优点:线程安全,延迟加载,性能较好。
-
缺点:实现稍显复杂。
5. 静态内部类(推荐,线程安全,延迟加载)
特点:利用类加载机制实现延迟加载,同时天然线程安全。
public class Singleton {
private Singleton() {}
// 静态内部类,在加载时初始化 Singleton 实例
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
-
优点:
-
延迟加载:
Holder类只有在第一次调用getInstance方法时才会加载并初始化实例。 -
线程安全:JVM 类加载机制保证线程安全。
-
6. 枚举单例(最简单,线程安全)
特点:利用枚举的特性实现单例。
public enum Singleton {
// 定义一个枚举元素,代表 Singleton 的唯一实例
INSTANCE;
// 单例类中的其他方法或变量
private int value;
// 初始化方法,可以在枚举的构造方法中进行初始化
Singleton() {
this.value = 42; // 假设默认值为 42
}
// 对外暴露的方法,可以操作或获取内部状态
public void someMethod() {
System.out.println("Singleton method invoked. Current value: " + value);
}
// Getter 和 Setter 方法
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
public class Main {
public static void main(String[] args) {
// 获取单例实例
Singleton instance = Singleton.INSTANCE;
// 调用方法
instance.someMethod(); // 输出: Singleton method invoked. Current value: 42
// 修改状态
instance.setValue(100);
System.out.println("Updated value: " + instance.getValue()); // 输出: Updated value: 100
}
}
-
优点:
-
线程安全:枚举本身是线程安全的。
-
防止反序列化创建新实例:枚举类型保证了单例。
-
-
缺点:不能进行懒加载,但推荐作为一种标准单例实现方式。
总结
| 实现方式 | 是否线程安全 | 是否延迟加载 | 优点 | 缺点 |
|---|---|---|---|---|
| 饿汉式 | 是 | 否 | 简单,线程安全 | 不使用时会浪费资源 |
| 懒汉式 | 否 | 是 | 延迟加载 | 多线程环境可能不安全 |
| synchronized 懒汉式 | 是 | 是 | 简单,线程安全 | 性能差 |
| 双重检查锁 | 是 | 是 | 性能较好,线程安全 | 实现复杂 |
| 静态内部类 | 是 | 是 | 延迟加载,线程安全,推荐使用 | 适用性广,缺点少 |
| 枚举单例 | 是 | 否 | 简洁,线程安全,防反序列化和反射攻击 | 不能延迟加载 |
推荐实现
-
常规场景:使用 静态内部类 或 枚举单例,线程安全且性能优越。
-
对性能要求极高:可以使用 双重检查锁

浙公网安备 33010602011771号