1. 介绍
单例模式(Singleton Pattern)是 Java 中最简单最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
主要用来解决频繁创建和销毁全局使用的类实例的问题。当需要控制实例数目,节省系统资源时使用。
-
优点
-
内存中只有一个实例,减少内存开销,尤其是频繁创建和销毁实例时(如管理学院首页页面缓存)。
-
避免资源的多重占用(如写文件操作)。
-
-
缺点
-
没有接口,不能继承。
-
与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心实例化方式。
-
2. 实现及相关代码
在 Java 中,单例模式(Singleton Pattern)的常见实现方式有 饿汉式(Eager Initialization) 和 懒汉式(Lazy Initialization) ,其中懒汉式又分为 线程不安全 和 线程安全(双重检查锁) 两种。
2.1 饿汉式(Eager Initialization)
特点:类加载时就初始化实例,线程安全,但可能浪费资源(如果实例未被使用)。
java
public class EagerSingleton {
// 类加载时就初始化实例
private static final EagerSingleton INSTANCE = new EagerSingleton();
// 私有构造方法,防止外部 new 实例
private EagerSingleton() {}
// 提供全局访问点
public static EagerSingleton getInstance() {
return INSTANCE;
}
}
优点:
-
线程安全(JVM 保证类加载时初始化)
-
实现简单
缺点:
- 如果实例未被使用,会造成资源浪费
2.2 懒汉式(Lazy Initialization)
2.2.1 线程不安全版本(不推荐)
java
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}
public static LazySingleton getInstance() {
if (instance == null) {
// 多线程下可能创建多个实例
instance = new LazySingleton();
}
return instance;
}
}
缺点:多线程环境下可能创建多个实例,不推荐使用。
2.2.2 线程安全版本(synchronized 方法)
java
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}
// 加 synchronized 保证线程安全,但性能较差
public static synchronized LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
缺点 :每次调用 getInstance() 都要加锁,性能较差。
2.2.3 双重检查锁(Double-Checked Locking,推荐)
java
public class LazySingleton {
// 使用 volatile 防止指令重排序
private static volatile LazySingleton instance;
private LazySingleton() {}
public static LazySingleton getInstance() {
if (instance == null) { // 第一次检查
synchronized (LazySingleton.class) { // 加锁
if (instance == null) { // 第二次检查
instance = new LazySingleton();
}
}
}
return instance;
}
}
优点:
-
线程安全
-
只有第一次初始化时加锁,后续调用无锁,性能较好
注意 :volatile 关键字防止 JVM 指令重排序,避免返回未初始化的实例。
2.3 静态内部类实现(推荐)
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()时才初始化) -
实现简单,无锁
3. 总结
| 实现方式 | 线程安全 | 懒加载 | 性能 | 适用场景 |
|---|---|---|---|---|
| 饿汉式 | ✅ | ❌ | ⭐⭐⭐ | 单例对象占用资源少,且一定会使用 |
| 懒汉式(synchronized) | ✅ | ✅ | ⭐ | 不推荐,性能差 |
| 双重检查锁(DCL) | ✅ | ✅ | ⭐⭐⭐ | 推荐,兼顾线程安全和性能 |
| 静态内部类 | ✅ | ✅ | ⭐⭐⭐ | 推荐,无锁,代码简洁 |
推荐:
-
如果单例对象占用资源少,且一定会使用 → 饿汉式
-
如果需要懒加载,且对性能有要求 → 双重检查锁 或 静态内部类