单例模式
-
- [**1. 饿汉式(Eager Initialization)**](#1. 饿汉式(Eager Initialization))
- [**2. 懒汉式(Lazy Initialization,非线程安全)**](#2. 懒汉式(Lazy Initialization,非线程安全))
- [**3. 线程安全的懒汉式(同步方法)**](#3. 线程安全的懒汉式(同步方法))
- [**4. 双重检查锁(Double-Checked Locking,推荐)**](#4. 双重检查锁(Double-Checked Locking,推荐))
- [**5. 静态内部类(推荐)**](#5. 静态内部类(推荐))
- [**6. 枚举单例(最推荐)**](#6. 枚举单例(最推荐))
- [**7. 通过 `ThreadLocal` 实现(每个线程单例)**](#7. 通过
ThreadLocal
实现(每个线程单例)) - **总结**
Java 实现单例模式的方式主要有以下几种,每种方式都有其优缺点和适用场景。
1. 饿汉式(Eager Initialization)
实现方式
java
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {} // 私有构造方法,防止外部实例化
public static Singleton getInstance() {
return INSTANCE;
}
}
优缺点
✅ 优点:
- 实现简单,类加载时即创建实例,线程安全。
- 访问速度快,调用
getInstance()
方法不会有同步开销。
❌ 缺点:
- 可能造成资源浪费:即使实例可能长期未使用,仍然会在类加载时创建。
适用场景
- 对象创建成本低 ,且类会被频繁使用的场景(如工具类)。
2. 懒汉式(Lazy Initialization,非线程安全)
实现方式
java
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
优缺点
✅ 优点:
- 只有在第一次调用时才创建实例,节省资源。
❌ 缺点:
- 非线程安全 :多个线程同时调用
getInstance()
可能导致多个实例被创建。
适用场景
- 单线程环境 ,或者不在多线程场景下使用。
3. 线程安全的懒汉式(同步方法)
实现方式
java
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,推荐)
实现方式
java
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. 静态内部类(推荐)
实现方式
java
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. 枚举单例(最推荐)
实现方式
java
public enum Singleton {
INSTANCE;
public void doSomething() {
System.out.println("Do something...");
}
}
优缺点
✅ 优点:
- 线程安全,由 JVM 保证。
- 防止反序列化破坏单例,因为枚举不会创建新的实例。
- 代码最简洁,推荐使用。
❌ 缺点:
- 无法懒加载,类加载时即创建实例。
- 不能继承其他类(但可以实现接口)。
适用场景
- 绝对保证单例性 的场景,如 数据库连接管理、日志管理器等。
7. 通过 ThreadLocal
实现(每个线程单例)
实现方式
java
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
)。
如果需要懒加载且高性能 ,推荐 静态内部类 或 双重检查锁。