C#实现单例模式的几种方法
单例模式,也叫单子模式,是一种常用的软件设计模式,属于创建型模式的一种。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。
单例模式在设计模式中可以说非常的典型,在面试中也是最多被问起的,以下是C#实现单例模式的几种方法:
第一种
public sealed class Singleton1
{
private static Singleton1 _singleton1;
private Singleton1()
{
Console.WriteLine("实例化一次!");
}
public Singleton1 CreateInstance()
{
return _singleton1 ??= new Singleton1();
}
}
单线程:
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
Singleton1.CreateInstance();
}
Console.ReadKey();
}
}
结果:
多线程:
class Program
{
static void Main(string[] args)
{
// for (int i = 0; i < 5; i++)
// {
// Singleton1.CreateInstance();
// }
for (int i = 0; i < 5; i++)
{
Task.Run(Singleton1.CreateInstance);
}
Console.ReadKey();
}
}
结果:
最简单的单例模式,但不适用于多线程
第二种
public sealed class Singleton2
{
private static Singleton2 _singleton2;
private static readonly object Singleton2Lock = new object();
private Singleton2()
{
Console.WriteLine("实例化一次!");
}
public static Singleton2 CreateInstance()
{
lock (Singleton2Lock)
{
return _singleton2 ??= new Singleton2();
}
}
}
直接上结果:
加了线程锁,多线程运行也没问题,但效率不高
第三种
public sealed class Singleton3
{
private static Singleton3 _singleton3;
private static readonly object Singleton3Lock = new object();
private Singleton3()
{
Console.WriteLine("实例化一次!");
}
public Singleton3 CreateInstance()
{
if (_singleton3==null)
{
lock (Singleton3Lock)
{
return _singleton3 ??= new Singleton3();
}
}
return _singleton3;
}
}
在lock前再加入if判断,减少后续线程不必要的等待,比较经典《双if+lock》的写法
第四种(推荐)
public sealed class Singleton4
{
private static readonly Singleton4 _singleton4=new Singleton4();
static Singleton4()
{
Console.WriteLine("实例化一次!");
}
public static Singleton4 CreateInstance()
{
return _singleton4;
}
}
我们知道C#会在调用静态构造函数时初始化静态变量,并且CLR会保证静态构造函数只被调用一次,这样我们就能保证Singleton4
只被实例化一次。运用CLR特性,并且代码足够简洁。
第五种(推荐)
public sealed class Singleton5
{
public static Singleton5 CreateInstance()
{
return Nested.Singleton5;
}
}
public class Nested
{
internal static readonly Singleton5 Singleton5 = new Singleton5();
static Nested()
{
Console.WriteLine("实例化一次!");
}
}
和第四种方法很像,不过这样可以做到按需创建,只要我们不调用Singleton5.CreateInstance
,Singleton5的实例就不会被创建。