什么是单例模式?

保障一个类只有一个实例,并提供一个全局变量来拜访这个实例,这就是单例模式,单例模式属于对象创立型模式。

单例模式的几个因素

  • 类只能有一个实例
  • 这个实例必须由该类自身创立
  • 该类必须向整个零碎提供该实例的拜访权限

单例模式的构造

单例模式的实现

class Singleton{    private static Singleton s_Instance;    //公有构造方法,避免内部实例化    private Singleton() { }    public static Singleton GetInstance()    {        if (s_Instance == null)            s_Instance = new Singleton();        return s_Instance;    }}

测试代码

static void Main(){    var s1 = Singleton.GetInstance();    var s2 = Singleton.GetInstance();    if (object.ReferenceEquals(s1, s2))        Console.WriteLine($"s1 s2两个实例是雷同的");    Console.ReadKey();}

后果

饿汉式单例与懒汉式单例

饿汉式单例(最简略的单例)

class EagerSingleton{    //类加载时执行    private static EagerSingleton s_Instance = new EagerSingleton();    private EagerSingleton() { }    public static EagerSingleton GetInstance()    {        return s_Instance;    }}

懒汉式单例

//懒汉式单例与饿汉式单例不同的在于:懒汉式单例在第一次被援用时将本人实例化(类被加载时不会实例化本身)class LazySingleton{    private static LazySingleton s_Instance;    //公有构造方法,避免内部实例化    private LazySingleton() { }    public static LazySingleton GetInstance()    {        if (s_Instance == null)            s_Instance = new LazySingleton();        return s_Instance;    }}

懒汉式单例的线程平安问题

在高并发多线程的环境下运行懒汉式单例的代码,会呈现在某一时刻存在多个线程同时拜访GetInstance办法,可能会创立多个实例,违反了单例模式的设计用意。

批改懒汉式单例代码使其线程平安

class LazySingleton{    private static readonly object s_LockObj = new object();    private static LazySingleton s_Instance;    //公有构造方法,避免内部实例化    private LazySingleton() { }    public static LazySingleton GetInstance()    {        if (s_Instance == null)        {            //加锁使程序在某一时刻只容许一个线程拜访            lock (s_LockObj)            {                if (s_Instance == null)                    s_Instance = new LazySingleton();            }        }        return s_Instance;    }}

为什么要双重校验

当实例不存在,并且多个线程同时调用GetInstance办法,此时它们都能通过第一重"s_Instance == null"的判断,此时只会有一个线程进入lock块执行创立代码,如果不进行第二次的"s_Instance == null"判断,当第一个线程创立完实例来到后,第二个线程进入lock块,因为第二个线程并不知道实例曾经被创立,将持续创立新的实例,还是会产生多个实例对象。

饿汉式单例与懒汉式单例比拟

饿汉式单例在类被加载时就创立实例对象,长处在于无需思考线程平安问题,因为单例对象一开始就创立好了,所以调用速度优于懒汉式单例。同时,因为类加载时就须要创立单例对象,因而从资源利用角度来说,饿汉式单例不如懒汉式单例,类的加载工夫绝对懒汉式单例也更慢。

懒汉式单例在第一次应用时创立单例对象,实现了提早加载,毋庸始终占用系统资源。然而懒汉式单例必须解决线程平安问题,这将导致系统性能受到肯定水平的影响。

单例模式的长处

  • 零碎中只存在一个对象,节约系统资源
  • 提供惟一一个实例,能够很好的管制如何拜访以及何使拜访它

单例模式的毛病

  • 没有形象层,单例类扩大艰难
  • 单例类将对象的创立和对象自身的性能耦合在一起,职责过重,在肯定水平上违反了类的繁多职责准则

在以下状况能够思考应用单例模式

  • 某一个对象在零碎中只须要一个或者因为实例化耗费太大只容许创立一个
  • 该实例只能通过一个公共拜访点拜访