单例模式
创建型模式
访问次数: 12
单例模式确保一个类只有一个实例,并提供一个全局访问点。
视频教程
类图
classDiagram
class Singleton {
-instance: Singleton
-Singleton()
+getInstance() Singleton
+operation()
}
Singleton --> Singleton : creates
源代码示例
// 懒汉式单例(线程不安全)
class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
public void operation() {
System.out.println("Singleton operation");
}
}
// 懒汉式单例(线程安全)
class ThreadSafeSingleton {
private static volatile ThreadSafeSingleton instance;
private ThreadSafeSingleton() {}
public static ThreadSafeSingleton getInstance() {
if (instance == null) {
synchronized (ThreadSafeSingleton.class) {
if (instance == null) {
instance = new ThreadSafeSingleton();
}
}
}
return instance;
}
}
// 饿汉式单例
class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return instance;
}
}
# 懒汉式单例(线程不安全)
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def operation(self):
print("Singleton operation")
# 懒汉式单例(线程安全)
import threading
class ThreadSafeSingleton:
_instance = None
_lock = threading.Lock()
def __new__(cls):
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
# 饿汉式单例(使用装饰器)
def singleton(cls):
instances = {}
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class EagerSingleton:
def __init__(self):
pass
# 使用示例
if __name__ == "__main__":
s1 = Singleton()
s2 = Singleton()
print(s1 is s2) # True
s1.operation()
应用场景
当系统中只需要一个实例,且需要全局访问时。应用场景包括:
1)数据库连接池,确保整个应用程序共享同一个连接池实例,避免资源浪费
2)日志记录器,全局统一的日志管理,确保日志格式和输出的一致性
3)配置管理器,系统配置信息只需要加载一次,全局共享访问
4)缓存管理器,应用程序级别的缓存实例,提供统一的缓存服务
5)线程池管理器,系统级别的线程资源管理,避免创建过多线程池实例
6)应用程序上下文,Spring等框架中的应用上下文,管理Bean的生命周期
精选场景详解 —— 数据库连接池:全局唯一共享实例
问题背景
若每个模块各自 new 一个连接池,会造成连接数暴涨、配置不一致,甚至拖垮数据库。系统需要「全进程共用一个池」。
模式如何解决
选用单例模式:ConnectionPool 构造函数私有,通过 getInstance() 提供唯一实例。所有 DAO/Repository 都从该实例借还连接。
要点:
1)保证全局唯一,资源可控;
2)懒加载或饿汉式按启动成本选择;
3)多线程下需正确同步(双重检查、静态内部类或语言级单例)。
注意:单例会引入全局状态,测试时可配合接口 + 可替换实现,避免过度耦合。在分布式多进程中,「进程内单例」并不等于「集群唯一」,集群级唯一需另用分布式协调。
场景模型(角色映射)
将模式中的抽象角色映射到该业务领域的具体类:
classDiagram
class ConnectionPool {
-instance: ConnectionPool
-connections: List~Connection~
-ConnectionPool()
+getInstance() ConnectionPool
+borrow() Connection
+release(conn: Connection)
}
class Connection {
+open()
+close()
+execute(sql: String)
}
class OrderRepository {
+findById(id: long) Order
}
class UserRepository {
+findById(id: long) User
}
ConnectionPool --> ConnectionPool : getInstance
ConnectionPool --> Connection
OrderRepository --> ConnectionPool
UserRepository --> ConnectionPool