设计模式之单例模式:一个类就只有一个实例
1. 介绍
单例模式(Singleton Pattern)是 Java 中最简单最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
主要用来解决频繁创建和销毁全局使用的类实例的问题。当需要控制实例数目,节省系统资源时使用。
- 优点 - 内存中只有一个实例,减少内存开销,尤其是频繁创建和销毁实例时(如管理学院首页页面缓存)。 
- 避免资源的多重占用(如写文件操作)。 
 
- 缺点 - 没有接口,不能继承。 
- 与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心实例化方式。 
 
2. 实现及相关代码
在 Java 中,单例模式(Singleton Pattern)的常见实现方式有 饿汉式(Eager Initialization) 和 懒汉式(Lazy Initialization),其中懒汉式又分为 线程不安全 和 线程安全(双重检查锁) 两种。
2.1 饿汉式(Eager Initialization)
特点:类加载时就初始化实例,线程安全,但可能浪费资源(如果实例未被使用)。
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 线程不安全版本(不推荐)
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 方法)
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,推荐)
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 静态内部类实现(推荐)
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) | ✅ | ✅ | ⭐⭐⭐ | 推荐,兼顾线程安全和性能 | 
| 静态内部类 | ✅ | ✅ | ⭐⭐⭐ | 推荐,无锁,代码简洁 | 
推荐:
- 如果单例对象占用资源少,且一定会使用 → 饿汉式 
- 如果需要懒加载,且对性能有要求 → 双重检查锁 或 静态内部类 
