设计模式-单例模式
目录
设计模式-单例模式
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
)。
如果 需要懒加载且高性能 ,推荐 静态内部类 或 双重检查锁 。