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