饿汉式单例与懒汉式单例的C#实现

来源:互联网 发布:php 服务器基础知识 编辑:程序博客网 时间:2024/06/06 02:58

      本文将介绍如何使用C#语言实现饿汉式单例汉式单例,并分析饿汉式单例与懒汉式单例的优缺点。

 

     1. 饿汉式单例类

      饿汉式单例类(Eager Singleton)是实现起来最容易的单例类,饿汉式单例类结构图如图1所示。

1 饿汉式单例类图

      从图1中可以看出,由于在定义静态变量的时候实例化单例类,因此在类加载时单例对象就已创建,代码如下:

class EagerSingleton {     private static EagerSingleton instance = new EagerSingleton();     private EagerSingleton() { }     public static EagerSingleton GetInstance()     {        return instance;     }}

      当类被加载时,静态变量instance 会被初始化,此时类的私有构造函数会被调用,单例类的唯一实例将被创建。

 

      2. 懒汉式单例类与双重检查锁定

      与饿汉式单例类相同之处是,懒汉式单例类(Lazy Singleton)的构造函数也是私有的。与饿汉式单例类不同的是,懒汉式单例类在第一次被引用时将自己实例化,在懒汉式单例类被加载时不会将自己实例化。懒汉式单例类结构图如图2所示。

图2  懒汉式单例类图

      从图2可以看出,在懒汉式单例类中,不是在定义静态变量时实例化单例类,而是在第一次调用静态工厂方法时实例化单例类。

      但是懒汉式单例存在一个很严重的问题:如果在高并发、多线程环境下实现懒汉式单例类,在某一时刻可能会有多个线程需要使用单例对象,即会有多个线程同时调用GetInstance()方法,可能会造成创建多个实例对象,这将违背单例模式的设计意图。为了防止生成多个单例对象,需要使用C#语言中的lock关键字lock关键字锁定的代码片段称之为临界区,可以确保当一个线程位于代码的临界区时,另一个线程不能进入临界区。如果其他线程试图进入锁定的代码,则将一直等待,直到该对象被释放为止。修改之后的懒汉式单例类代码如下:

class LazySingleton {     private static LazySingleton instance = null;     //程序运行时创建一个静态只读的辅助对象    private static readonly object syncRoot = new object();    private LazySingleton() { }     public static LazySingleton GetInstance()     {         //第一重判断,先判断实例是否存在,不存在再加锁处理        if (instance == null)         {            //加锁的程序在某一时刻只允许一个线程访问            lock(syncRoot)            {                //第二重判断                if(instance==null)                {                    instance = new LazySingleton();  //创建单例实例                }            }        }        return instance;     }}

      在上面给出的懒汉式单例类实现代码中,对静态工厂方法GetInstance()中创建单例对象的代码进行了加锁,由于在调用时无法确定该单例对象是否已创建,因此需要使用辅助对象syncRoot来进行代码锁定。为了不影响程序的性能,此处只锁定创建单例对象的代码,并未锁定整个方法。如果实例存在则直接返回,如果实例未创建则加锁后再创建。

      为了更好地对单例对象的创建进行控制,此处使用了一种被称之为双重检查锁定(Double-CheckLocking)的双重判断机制。在双重检查锁定中,当实例不存在且同时有两个线程调用GetInstance()方法时,它们都可以通过第一重“instance==null”判断,然后由于lock锁定机制,只有一个线程进入lock中执行创建代码,另一个线程处于排队等待状态,必须等待第一个线程执行完毕后才可以进入lock锁定的代码,如果此时不进行第二重“instance==null”判断,第二个线程并不知道实例已经创建,将继续创建新的实例,还是会产生多个单例对象,违背单例模式的设计思想,因此需要进行双重检查。

 

      3. 饿汉式单例类与懒汉式单例类比较

       饿汉式单例类在类被加载时就将自己实例化,它的优点在于无须考虑多个线程同时访问的问题,可以确保实例的唯一性;从调用速度和反应时间角度来讲,由于单例对象一开始就得以创建,因此要优于懒汉式单例。但是无论系统在运行时是否需要使用该单例对象,由于在类加载时该对象就需要创建,因此从资源利用效率角度来讲,饿汉式单例不及懒汉式单例,而且在系统加载时由于需要创建饿汉式单例对象,加载时间可能会比较长。

      懒汉式单例类在第一次使用时创建,无须一直占用系统资源,实现了延迟加载,但是必须处理好多个线程同时访问的问题,特别是当单例类作为资源控制器,在实例化时必然涉及资源初始化,而资源初始化很有可能耗费大量时间,这意味着出现多线程同时首次引用此类的机率变得较大,需要通过双重检查锁定等机制进行控制,这将导致系统性能受到一定影响。

 

      Java程序员可进一步阅读:确保对象的唯一性——单例模式 (三)与 确保对象的唯一性——单例模式 (四)

 

  【作者:刘伟  http://blog.csdn.net/lovelion

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 rh阴性血要二胎怎么办 全血粘度都偏高怎么办 血脂高血粘度高怎么办 全血粘度值1偏高怎么办 全血粘度3偏高怎么办 血粘度高的症状怎么办 粉瘤感染化脓了怎么办 乌药剂量用大了怎么办 水卡消磁了怎么办妙招 电卡消磁了怎么办妙招 入园磁卡消磁了怎么办 透析中静脉压高怎么办 腰间盘突出压迫神经腿疼怎么办 肺热引起的发烧怎么办 肺热引起的痘痘怎么办 冰箱压条的霉点怎么办 白色的布鞋变黄怎么办 白鞋橡胶变黄了怎么办 肝功能检查总胆汁酸高怎么办 吃丹参滴丸尿血怎么办 胰酶消化过久怎么办 抗凝血酶活性低怎么办 抗凝血酶3偏低怎么办 抗凝血酶ⅲ低 怎么办 抗凝血酶3抗原高怎么办 孕32周血压高怎么办 智齿血凝块掉了怎么办 入职体检alt偏高怎么办 剖腹产后crp值高怎么办 超敏c反应蛋白偏高怎么办 孕妇c反应蛋白高怎么办 婴儿超敏crp偏高怎么办 小孩c反应蛋白高怎么办 发烧c反应蛋白高怎么办 孕妇快生了贫血怎么办 小孩吃糖牙齿痛怎么办 前门牙掉了一块怎么办 吃冷东西牙疼怎么办 吃甜的立刻牙疼怎么办 吃甜的牙疼怎么办 孕妇甲功t4偏低怎么办