设计模式-单例模式
单例模式(Singleton Pattern)解释
定义
单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点来获取它。
单例模式的特点
- 全局唯一性:单例类只能有一个实例。
- 全局访问点:通过提供一个静态方法或属性,允许其他类访问该唯一实例。
- 懒加载:实例在第一次使用时创建,避免不必要的资源消耗(可选)。
单例模式的实现方式
以下用 Java 示例讲解常见的单例模式实现方式。
1. 饿汉式(Eager Initialization)
在类加载时就创建实例,线程安全,但如果实例未被使用会浪费资源。
public class Singleton {
// 静态实例,类加载时初始化
private static final Singleton INSTANCE = new Singleton();
// 私有构造方法,防止外部实例化
private Singleton() {}
// 提供全局访问点
public static Singleton getInstance() {
return INSTANCE;
}
}
优点:实现简单,线程安全。
缺点:类加载时就创建实例,即使未使用也会占用资源。
2. 懒汉式(Lazy Initialization)
在需要时才创建实例,线程不安全。
public class Singleton {
private static Singleton instance;
// 私有构造方法
private Singleton() {}
// 提供全局访问点
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
优点:实例在第一次使用时创建,避免资源浪费。
缺点:多线程环境下可能导致线程安全问题。
3. 线程安全的懒汉式
通过 synchronized
关键字解决线程安全问题。
public class Singleton {
private static Singleton instance;
private Singleton() {}
// 提供线程安全的全局访问点
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
优点:线程安全,懒加载。
缺点:性能较低,每次获取实例时都需要同步。
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
关键字确保变量可见性。
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;
}
}
优点:线程安全,懒加载,性能高。
缺点:实现稍复杂。
6. 枚举单例
通过枚举实现单例模式,是最简单和推荐的方式之一。
public enum Singleton {
INSTANCE;
public void doSomething() {
System.out.println("单例方法调用");
}
}
优点:天生线程安全,防止反序列化破坏单例,代码简单。
缺点:不支持延迟加载(但通常这不是问题)。
测试单例模式
public class SingletonTest {
public static void main(String[] args) {
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
System.out.println(singleton1 == singleton2); // true,两个引用指向同一个实例
}
}
单例模式的优缺点
优点
- 唯一实例:确保系统中只有一个对象,节省资源。
- 全局访问:提供一个全局访问点,便于管理。
缺点
- 扩展困难:由于类只能有一个实例,继承和扩展较难。
- 并发问题:某些实现方式在多线程环境下可能不安全。
使用场景
- 日志记录器:系统中的日志类只需要一个实例。
- 配置管理:全局配置类,避免重复加载配置。
- 数据库连接池:确保多个模块共享同一个连接池。
- 线程池:单例模式可用于管理线程池的全局访问。
通过以上方式,可以根据需求和场景选择合适的单例模式实现方式。