- 单例模式:
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
为了解决两个问题:
//简单单例
class Singleton
{
private static Singleton instance;
private Singleton()
{
}
public static Singleton GetInstance()
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
//客户端代码
static void Main(string[] args)
{
Singleton s1 = Singleton.GetInstance();
Singleton s2 = Singleton.GetInstance();
if(s1 == s2){
Console.WriteLine("两个对象是相同的实例");
}
Console.Read();
}
- 多线程单例
当多个线程同时访问 Singleton 类的时候,会有可能创建出多个实例。这时就需要一把 lock 来确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,那么它将一直等待,直到该对象被释放。
//多线程单例
class Singleton
{
private static Singleton instance;
private static readonly object syncRoot = new object();
private Singleton()
{
}
//这样做的缺点就是 每次创建的时候都需要 lock。
// public static Singleton GetInstance()
// {
// lock(syncRoot)
// {
// if(instance == null)
// {
// instance = new Singleton();
// }
// }
// return instance;
// }
//先判断实例是否存在,不存在再加锁处理
public static Singleton GetInstance()
{
//判断两次实例是否为null 的道理在于,第一次判断是为了避免频繁加锁
/*第二次判断是为了防止多线程多次创建实例当多个线程同时访问的时候,会允许一个线程进去,当一个线程创建完对象之后,另一个线程进入如果不判断非空的情况,那么也会出现重复创建的情况。*/
if(instance == null){
lock(syncRoot){
if(instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
//这种静态初始化方式是在自己被加载的时候就将自己实例化,上面的在第一次被引用的时候才会将自己实例化,属于懒加载。
public sealed class Singleton
{
//在第一次引用类的任何成员时创建实例。公共语言运行库负责处理变量初始化
private static readonly Singleton instance = new Singleton();
private Singleton(){}
public static Singleton GetInstance()
{
return instance;
}
}