关于C#中实现单例模式
单例模式是设计模式中非常经典的模式,用于在程序全局下只创建一个实例访问,常用于需要创建唯一性的地方,在C#中也有很多方法可以实现单例模式,在这里记录一下,但是兼顾优雅和性能的创建方法并不多。
- 版本一 懒汉式 原始简易版 非线程安全 不可用
在多线程下,可能多个线程都判断instance == null为true,创建多个实例
public sealed class Singleton
{
private static Singleton instance = null ;
private Singleton()
{
}
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
- 版本二 懒汉式 简单的线程安全 不推荐使用
主要问题在于,每次获取实例都需要加锁,这会带来性能损耗
public sealed class Singleton
{
private static Singleton instance = null;
private static readonly object padlock = new object();
Singleton()
{
}
public static Singleton Instance
{
get
{
lock (padlock)
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
}
- 版本三 懒汉式 使用双重检查锁定尝试线程安全 可用 不推荐
这是版本二的改良版,避免每次获取实例都加锁,只有当在创建实例时才进行加锁,但是依然存在一些缺点:
- 它在Java中不起作用,在C#中习惯这么写到了java中可能导致错误。Java内存模型无法确保构造函数在将新对象的引用分配给Instance之前完成。Java内存模型经历了1.5版本的重新改进,但是在没有volatile变量(如在C#中)的情况下,双重检查锁定仍然会被破坏。
- 性能不是最优的
public sealed class Singleton
{
private static Singleton instance = null;
private static readonly object padlock = new object();
Singleton()
{
}
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (padlock)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
}
- 版本四 不太懒,不使用锁且线程安全 可用
C#中的静态构造函数仅在创建类的实例或引用静态成员时执行,并且每个AppDomain只执行一次。
但是如果有Instance之外的静态成员,那么对这些成员的第一次引用将创建实例,所以并不是完全懒惰。
public sealed class Singleton
{
private static readonly Singleton instance = new Singleton();
// 显式静态构造函数告诉C#编译器
// 不要将类型标记为BeforeFieldInit
static Singleton()
{
}
private Singleton()
{
}
public static Singleton Instance
{
get
{
return instance;
}
}
}
- 版本五 完全懒惰 可用
在这里,实例化是由对嵌套类的静态成员的第一次引用触发的,该引用只发生在Instance中。这意味着实现是完全懒惰的,但是具有前面实现的所有性能优势。请注意,尽管嵌套类可以访问封闭类的私有成员,但反之则不然,因此需要instance在此处为内部成员。不过,这不会引起任何其他问题,因为类本身是私有的。但是,为了使实例化变得懒惰,代码要稍微复杂一些。
public sealed class Singleton
{
private Singleton()
{
}
public static Singleton Instance { get { return Nested.instance; } }
private class Nested
{
// 显式静态构造告诉C#编译器
// 未标记类型BeforeFieldInit
static Nested()
{
}
internal static readonly Singleton instance = new Singleton();
}
}
- 版本六 使用 Lazy 类型,可以很简单的实现懒加载,而且提供线程安全选项,推荐
线程安全性
默认情况下,Lazy
public sealed class Singleton
{
private static readonly Lazy<Singleton> lazy = new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance { get { return lazy.Value; } }
private Singleton()
{
}
}
Lazy有多个构造函数,Lazy
此外,Lazy