vlambda博客
学习文章列表

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的实例就不会被创建。