概念
单例模式是一种常用的软件设计模式,其目的是确保一个类仅有一个实例,并提供一个全局访问点来获取这个实例。单例模式在需要控制资源访问(如配置文件读取器、数据库连接池等)时非常有用,因为它可以防止资源的多次初始化,确保所有访问都通过同一实例进行。
角色
在单例模式中,通常只涉及一个角色:
- 单例类(Singleton Class):这个类负责创建自己的唯一实例,并提供一个全局访问点来获取这个实例。
好处
- 控制资源访问:确保对共享资源的访问是同步的,防止了多个实例之间的冲突。
- 节省内存:由于只有一个实例,避免了重复创建对象造成的内存浪费。
- 全局访问点:提供了一个全局访问点来获取对象实例,简化了对共享资源的访问。
应用场景
- 配置文件的读取:应用程序的配置信息通常在整个应用程序中是共享的,使用单例模式可以确保配置信息的唯一性和一致性。
- 数据库连接池:数据库连接是一种昂贵的资源,使用单例模式可以管理一个连接池,减少连接的开销。
- 线程池:在多线程应用程序中,线程池可以管理一组线程的创建、销毁和复用,使用单例模式可以保证线程池的唯一性。
双重检查锁定的懒汉式单例模式
/// <summary>
/// 双重检查锁定的懒汉式单例模式
/// </summary>
public sealed class SingletonLazyChecked
{
// 私有静态变量,用于存储单例实例
// 使用volatile关键字确保多线程环境下的正确读取
private static volatile SingletonLazyChecked _instance;
// 私有静态对象,用于线程同步
private static readonly object _lock = new object();
// 私有构造函数,防止外部实例化
private SingletonLazyChecked()
{
// 在这里可以添加初始化代码
// 例如:初始化资源、配置等
}
// 公共静态属性,提供访问单例的入口
public static SingletonLazyChecked Instance
{
get
{
// 第一次检查实例是否存在
if (_instance == null)
{
// 锁定,防止多个线程同时进入
lock (_lock)
{
// 第二次检查实例是否存在,防止多个线程同时创建实例
_instance ??= new SingletonLazyChecked();
}
}
// 返回实例
return _instance;
}
}
// 这里可以添加单例的方法或属性
// 例如:public void SomeMethod() { ... }
}
-
volatile关键字:在
_instance
字段前使用volatile
关键字,这是为了确保在多线程环境中,对该字段的读取操作是直接从主内存中进行的,而不是从某个线程的缓存中读取,从而避免了因缓存不一致导致的问题。 -
双重检查锁定:
- 第一次检查
_instance
是否为null
,如果不为null
则直接返回实例,避免了不必要的锁操作,提高了效率。 - 如果为
null
,则进入lock
块,此时只有一个线程能进入该块。 - 在
lock
块内再次检查_instance
是否为null
,这是为了处理在第一次检查和获取锁之间,其他线程可能已经创建了实例的情况。 - 如果
_instance
仍然为null
,则创建新实例并赋值给_instance
。
- 第一次检查
-
私有构造函数:通过将构造函数设为私有,防止了类的外部通过
new
关键字创建实例。
Lazy<T>
的懒汉式单例模式
/// <summary>
/// 使用Lazy<T>的懒汉式单例模式
/// </summary>
public sealed class SingletonLazy
{
// 私有静态Lazy<T>字段,用于延迟创建SingletonLazy的实例
// Lazy<T>会自动处理线程安全和延迟初始化
private static readonly Lazy<SingletonLazy> lazyInstance = new Lazy<SingletonLazy>(() => new SingletonLazy());
// 私有构造函数,防止外部实例化
private SingletonLazy()
{
// 在这里可以添加初始化代码
// 例如:初始化资源、配置等
}
// 公共静态属性,提供访问单例的入口
public static SingletonLazy Instance
{
// 当访问Instance属性时,Lazy<T>会自动处理线程安全和延迟初始化
get { return lazyInstance.Value; }
}
// 这里可以添加单例的方法或属性
// 例如:public void AnotherMethod() { ... }
}
总结
单例模式是一种简单而强大的设计模式,它通过确保一个类只有一个实例并提供全局访问点来简化资源管理。
- 双重检查锁定的懒汉式单例:通过双重检查锁定机制确保在多线程环境下实例的唯一性和线程安全。但实现相对复杂,且需要正确处理
volatile
关键字和锁的使用。 - 使用
Lazy<T>
的懒汉式单例:利用C#内置的Lazy<T>
类,以更简洁的方式实现懒汉式单例模式。Lazy<T>
类自动处理线程安全和延迟初始化,使得代码更加简洁和易于维护。这是现代C#开发中推荐的单例实现方式之一。