单例模式(Singleton Pattern)
定义:Ensure a class has only one instance, and provide a global point of access to it.(确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。)
使用场景:
1)要求生成唯一序列号的环境;
2)在整个项目中需要一个共享访问点或共享数据,例如一个Web页面上的计数器,可以不用把每次刷新都记录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的;
3)创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源;
4)需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式(当然,也可以直接声明为static的方式)。
通用代码:(是线程安全的)
public class Singleton
{
/// <summary>
/// 自己主动创建实例
/// </summary>
private static readonly Singleton instance = new Singleton();
/// <summary>
/// 私有构造函数,限制产生多个对象
/// </summary>
private Singleton()
{
}
/// <summary>
/// 通过该方法获得实例对象
/// </summary>
/// <returns></returns>
public static Singleton GetInstance()
{
return instance;
}
/// <summary>
/// 类中其他方法,尽量是static
/// </summary>
public static void DoSomething()
{
}
}
线程不安全实例:
public class Singleton2
{
private static Singleton2 instance = null;
/// <summary>
/// 私有构造函数,限制产生多个对象
/// </summary>
private Singleton2()
{
}
/// <summary>
/// 通过该方法获得实例对象
/// </summary>
/// <returns></returns>
public static Singleton2 GetInstance()
{
if (instance == null)
{
instance = new Singleton2();
}
return instance;
}
/// <summary>
/// 类中其他方法,尽量是static
/// </summary>
public static void DoSomething()
{
}
}
上面的单例模式的实现在单线程下确实是完美的,然而在多线程的情况下会得到多个Singleton实例,因为在两个线程同时运行GetInstance方法时,此时两个线程判断(instance ==null)这个条件时都返回真,此时两个线程就都会创建Singleton的实例,这样就违背了我们单例模式初衷了,既然上面的实现会运行多个线程执行,那我们对于多线程的解决方案自然就是使GetInstance方法在同一时间只运行一个线程运行就好了,也就是我们线程同步的问题了
解决办法:
在 instance 变量前 添加 volatile 关键字,再添加一个同步锁对象,保证线程安全。
public class Singleton3
{
/// <summary>
/// volatile 关键字指示一个字段可以由多个同时执行的线程修改。
/// 声明为 volatile 的字段不受编译器优化(假定由单个线程访问)的限制。
/// 这样可以确保该字段在任何时间呈现的都是最新的值。
/// volatile 修饰符通常用于由多个线程访问但不使用 lock 语句对访问进行序列化的字段。
/// </summary>
private volatile static Singleton3 instance = null;
/// <summary>
/// 同步锁对象
/// </summary>
private static readonly object _lockSyncObject = new object();
/// <summary>
/// 私有构造函数,限制产生多个对象
/// </summary>
private Singleton3()
{
}
/// <summary>
/// 通过该方法获得实例对象
/// </summary>
/// <returns></returns>
public static Singleton3 GetInstance()
{
if (instance == null)
{
lock (_lockSyncObject)
{
instance = new Singleton3();
}
}
return instance;
}
/// <summary>
/// 类中其他方法,尽量是static
/// </summary>
public static void DoSomething()
{
}
}