单例模式
- **1. 饿汉式(Eager Initialization)**
- **实现方式**
- **优缺点**
- **适用场景**
- **2. 懒汉式(Lazy Initialization,非线程安全)**
- **实现方式**
- **优缺点**
- **适用场景**
- **3. 线程安全的懒汉式(同步方法)**
- **实现方式**
- **优缺点**
- **适用场景**
- **4. 双重检查锁(Double-Checked Locking,推荐)**
- **实现方式**
- **优缺点**
- **适用场景**
- **5. 静态内部类(推荐)**
- **实现方式**
- **优缺点**
- **适用场景**
- **6. 枚举单例(最推荐)**
- **实现方式**
- **优缺点**
- **适用场景**
- **7. 通过 `ThreadLocal` 实现(每个线程单例)**
- **实现方式**
- **优缺点**
- **适用场景**
- **总结**
Java 实现单例模式的方式主要有以下几种,每种方式都有其优缺点和适用场景。
1. 饿汉式(Eager Initialization)
实现方式
public class Singleton {private static final Singleton INSTANCE = new Singleton();private Singleton() {} // 私有构造方法,防止外部实例化public static Singleton getInstance() {return INSTANCE;}
}
优缺点
✅ 优点:
- 实现简单,类加载时即创建实例,线程安全。
- 访问速度快,调用
getInstance()
方法不会有同步开销。
❌ 缺点:
- 可能造成资源浪费:即使实例可能长期未使用,仍然会在类加载时创建。
适用场景
- 对象创建成本低,且类会被频繁使用的场景(如工具类)。
2. 懒汉式(Lazy Initialization,非线程安全)
实现方式
public class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}
优缺点
✅ 优点:
- 只有在第一次调用时才创建实例,节省资源。
❌ 缺点:
- 非线程安全:多个线程同时调用
getInstance()
可能导致多个实例被创建。
适用场景
- 单线程环境,或者不在多线程场景下使用。
3. 线程安全的懒汉式(同步方法)
实现方式
public class Singleton {private static Singleton instance;private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}
优缺点
✅ 优点:
- 线程安全,可确保只有一个实例被创建。
❌ 缺点:
synchronized
关键字会影响性能,每次调用getInstance()
都会加锁。
适用场景
- 需要保证线程安全,但实例创建不会频繁调用的场景。
4. 双重检查锁(Double-Checked Locking,推荐)
实现方式
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;}
}
优缺点
✅ 优点:
- 线程安全,只有在第一次调用时才会加锁,后续调用不会影响性能。
- 结合了懒加载和高效访问的优点。
❌ 缺点:
- 需要使用
volatile
防止指令重排序,Java 1.5 之前的版本不支持。
适用场景
- 多线程环境,且性能要求较高的场景。
5. 静态内部类(推荐)
实现方式
public class Singleton {private Singleton() {}private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance() {return SingletonHolder.INSTANCE;}
}
优缺点
✅ 优点:
- 线程安全,利用 JVM 类加载机制保证只会初始化一次。
- 只有在调用
getInstance()
时才会创建实例,节省资源(懒加载)。 - 无锁,性能高。
❌ 缺点:
- 无法传递参数,如果需要参数化实例,则无法使用该方法。
适用场景
- 高并发环境,且希望使用懒加载的场景。
6. 枚举单例(最推荐)
实现方式
public enum Singleton {INSTANCE;public void doSomething() {System.out.println("Do something...");}
}
优缺点
✅ 优点:
- 线程安全,由 JVM 保证。
- 防止反序列化破坏单例,因为枚举不会创建新的实例。
- 代码最简洁,推荐使用。
❌ 缺点:
- 无法懒加载,类加载时即创建实例。
- 不能继承其他类(但可以实现接口)。
适用场景
- 绝对保证单例性的场景,如 数据库连接管理、日志管理器等。
7. 通过 ThreadLocal
实现(每个线程单例)
实现方式
public class ThreadLocalSingleton {private static final ThreadLocal<ThreadLocalSingleton> instance =ThreadLocal.withInitial(ThreadLocalSingleton::new);private ThreadLocalSingleton() {}public static ThreadLocalSingleton getInstance() {return instance.get();}
}
优缺点
✅ 优点:
- 线程隔离,每个线程都有自己独立的实例。
- 避免了全局同步,适用于多线程数据隔离场景。
❌ 缺点:
- 无法做到全局唯一单例,只在单个线程内保持单例。
适用场景
- 每个线程需要独立状态的场景,如用户会话、数据库连接。
总结
方式 | 线程安全 | 是否懒加载 | 优点 | 缺点 | 适用场景 |
---|---|---|---|---|---|
饿汉式 | ✅ | ❌ | 实现简单,访问快 | 可能造成资源浪费 | 适用于常用单例 |
懒汉式 | ❌ | ✅ | 按需加载,节省资源 | 线程不安全 | 仅限单线程 |
同步懒汉 | ✅ | ✅ | 线程安全 | synchronized 影响性能 | 适用于低频率调用 |
双重检查锁 | ✅ | ✅ | 线程安全,性能优 | 代码较复杂 | 推荐,高并发环境 |
静态内部类 | ✅ | ✅ | 线程安全,懒加载 | 无法传参 | 推荐,JVM 保证 |
枚举单例 | ✅ | ❌ | 最安全,防反序列化 | 不能继承类 | 最推荐,绝对单例 |
ThreadLocal | ✅ | ✅ | 线程隔离 | 不是全局单例 | 适用于每线程独立实例 |
如果要保证绝对的单例性,推荐 枚举单例(Enum
)。
如果需要懒加载且高性能,推荐 静态内部类或 双重检查锁。