802 字
4 分钟

单例模式

发布于 2025-02-07

1. 基本介绍#

单例模式(Singleton Pattern)保证一个类只有一个实例,并通过全局访问点获取它。它适合需要在应用中共享同一实例的场景。

单例模式的关键点:#

  1. 唯一性:类只能有一个实例,确保系统中只会有这个唯一的对象。
  2. 全局访问:提供一个全局访问点来获取该实例。通常通过一个静态方法来获取实例。

单例模式的应用场景:#

  • 日志记录器:全局唯一的日志工具类。
  • 数据库连接池:多个线程共享一个数据库连接池。
  • 线程池:线程池是全局唯一的,避免重复创建。
  • 缓存管理:全局唯一的缓存对象。

2. 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)#

在第一次调用 getInstance() 时创建实例,节省资源,但需要处理多线程问题。

(1)非线程安全的懒汉式:多线程环境下可能会创建多个实例

public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}

(2)线程安全的懒汉式(加锁):每次调用 getInstance() 都会加锁,性能较差。

public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}

3. 双重检查锁(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 关键字防止指令重排序。

4. 静态内部类(Static Inner Class)#

利用类加载机制保证线程安全,同时实现懒加载。

public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
  • 优点:线程安全,懒加载,实现简单。
  • 缺点:无法传递参数初始化实例。

5. 枚举(Enum)#

利用枚举的特性实现单例,线程安全且防止反射攻击。

public enum Singleton {
INSTANCE;
public void doSomething() {
System.out.println("Doing something...");
}
}
  • 优点:线程安全,防止反射和序列化破坏单例。
  • 缺点:不够灵活(如无法延迟加载)。

6. ThreadLocal 单例#

为每个线程提供一个单例实例,线程间隔离。

public class ThreadLocalSingleton {
private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance =
ThreadLocal.withInitial(ThreadLocalSingleton::new);
private ThreadLocalSingleton() {}
public static ThreadLocalSingleton getInstance() {
return threadLocalInstance.get();
}
}
  • 优点:线程间隔离,适合线程内单例场景。
  • 缺点:每个线程都有自己的实例,不是全局单例。
单例模式
https://mj3622.github.io/posts/编程实践/单例模式/
作者
Minjer
发布于
2025-02-07
许可协议
CC BY-NC-SA 4.0