不好的解法-:只适用于单线程环境
public sealed class Singleton1
{
private Singleton1()
{
}
private static Singleton1 instance = null;
public static Singleton1 Instance
{
get
{
if(instance==null)
instance=new Singleton1();
return instance;
}
}
}
设想如果两个线程同时运行到判断instance是否为null的if语句,并且instance的确没有创建时,那么两个线程都会创建一个实例,此时类型Singleton1就不再满足单例模式的要求了。
不好的解法二:虽然在多线程环境中能工作,但效率不高
public sealed class Singleton2
{
private Singleton2() { }
private static readonly object syncObj=new object();
private static Singleton2 instance = null;
public static Singleton2 Instabce
{
get
{
lock (syncObj)
{
if(instance==null)
instance=new Singleton2();
}
return instance;
}
}
}
我们每次通过属性 Instance得到Singleton2的实例,都会试图加上一个同步锁,而加锁是一个非常耗时的操作,在没有必要的时候我们应该尽量避免。
可行的解法:加同步锁前后两次判断实例是否已经存在
public sealed class Singleton3
{
private Singleton3()
{
}
private static object syncObj=new object();
private static Singleton3 instance = null;
public static Singleton3 Instance
{
get
{
if (instance == null)
{
lock (syncObj)
{
if(instance==null)
instance=new Singleton3();
}
}
return instance;
}
}
}
Singleton3用加锁机制来确保在多线程环境下只创建一个实例,并且用两个 if 判断来提高效率。
强烈推荐的解法一:利用静态构造函数
C#的语法中有一个函数能够确保只调用一次,那就是静态构造函数,我们可以利用C#这个特性实现单例模式如下:
public sealed class Singleton4
{
private Singleton4(){}
private static Singleton4 instance=new Singleton4();
public static Singleton4 Instance
{
get { return instance; }
}
}
在 Singleton4 中,实例 instance 并不是第一次调用属性 Singleton4.Instance的时候创建,而是在第一次用到Singleton4的时候就会被创建。
强烈推荐的解法二:实现按需创建实例
最后的一个实现Singleton5则很好地解决了Singleton4中的实例创建时机过早的问题:
public sealed class Singleton5
{
Singleton5()
{
}
public static Singleton5 Instance
{
get { return Nested.instance; }
}
class Nested
{
static Nested(){}
internal static readonly Singleton5 instance=new Singleton5();
}
}
说明:
在前面的 5 种实现单例模式的方法中,第一种方法在多线程环境中不能正常工作,第二种模式虽然能在多线程环境中正常工作但时间效率很低,都不是面试官期待的解法。在第三种方法中我们通过两次判断一次加锁确保在多线程环境能高效率地工作。第四种方法利用C#的静态构造函数的特性,确保只创建一个实例。第五种方法利用私有嵌套类型的特性,做到只在真正需要的时候才会创建实例,提高空间使用效率。
网友评论