C# 中实现单例模式

时间:2015-06-09 06:06:37   收藏:0   阅读:1342

文章目录

简介

  单例模式是软件工程中广为人知的设计模式。单例模式就是指一个永远只能实例化一次。使用的方式是调用类里创建的静态方法。通常来说,单例模式创建的类,都是不带形参的 ,原因就是当创建多个实例的时候,如果参数不同的话(比如2个不同的重载构造函数),那么就会造成一些不必要的问题(如果相同的实例要被创建而且他们使用相同的参数的话,那么建议使用工厂模式),这篇文章的定位就是没有 任何的参数的情况下,通常情况下,单例模式是LAZY的,也就是说相当的容易创建。

  在C#中实现单例模式有很多种方式。我将在下面以上面的目录的形式呈现给大家,开始我会跟大家介绍最常用的单例模式的写法,这些写法的线程并不安全,然后会提到懒汉式写法(Lazy-Load),然后就是线程安全,最后会跟大家介绍一下提高效率的方式。

  所有的实现将会用通俗的语言来介绍,但是要注意以下:

  注意所有的实现都是用一个公共的且静态的属性作为实例的入口。在所有的情况下属性可以方便的转换成方法,而且和线程安全或者效率不冲突。

第一个版本 -  非线程安全

// 不要用这种方式
public sealed class Singleton
{
    private static Singleton instance=null;

    private Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            if (instance==null)
            {
                instance = new Singleton();
            }
            return instance;
        }
    }
}

  我要表明的是,上面的方法是非线程安全的,2个不同的线程可以同时进入这个方法,如果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;
            }
        }
    }
}

  上述实现是线程安全的。这个线程在共享的object上取出了一把锁,然后在创建实例以前检查这个实例是否被创建了。这个保护了内存屏障问题(lock保证了所有的读取操作是在LOCK获得以后发生的,所有的unlock保证了所有的写操作在lock 释放以后发生的),这样就保证了一个线程只能创建一个实例(每次只有一个线程在这段代码中运行),不巧的是,性能上来说,锁变成了每次都必须的当这个实例被响应的时候。

  注意除了在锁当中锁住typeof(Singleton)这种类型的以外,我锁住了一个静态私有的变量,对于这个类来说。如果是锁 的一个对象的话,其他的类可以进入并且锁住(比如Type)这样会造成性能风险的问题甚至死锁。这是我的大体偏好 - 也许可能的话,只有锁住对象才能达到最终的目的,或者某些文章说锁是为了达到一些特别的目的。(比如等待或者脉冲一个队列)。通常来说这样的对象应该被设置成私有的。这样会让写线程安全更加的容易。

 

第三个版本 - 尝试线程安全(双重锁定)

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;
        }
    }
}

  这个实现尝试了线程安全,当然并没必要每次都要取出lock,但是这种方式有如下4个缺点:

第四个版本 -  不完全lazy,但是线程安全且不用用锁

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();

    // 显示的static 构造函数
    //没必要标记类型 - 在field初始化以前
    static Singleton()
    {
    }

    private Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            return instance;
        }
    }
}

 

未完待续,原文链接地址:

http://csharpindepth.com/Articles/General/Singleton.aspx#unsafe

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!