`

C# 单例模式整理

阅读更多

参考:


方式1. 非线程安全

 

public class Singleton
{
    private static Singleton instance = null;

    private Singleton() { }

    public static Singleton GetInstance()
    {
        if (instance == null)
        {
            instance = new Singleton();
        }

        return instance;
    }
}

可能有两个线程都执行了 'if (instance==null)',且得到的结果都是 true,然后两个线程各自创建一个实例。

(有可能在执行 'if (instance==null)' 前,实例就已经创建好了,但是 memory model 不能保证其它线程能及时发现 instance 的值已经改变。(内存栅栏,memory barrier))

 

 

方式2. 简单的线程安全

 

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

    private static Singleton instance = null;

    private Singleton() { }

    public static Singleton GetInstance()
    {
        lock (s_lock)
        {
            if (instance == null)
            {
                instance = new Singleton();
            }

            return instance;
        }
    }
}

lock 可以消除内存栅栏的影响。

 

在CLR 中,任何锁方法的调用都构成了一个完整的内存栅栏,在栅栏之前写入的任何变量都必须在栅栏之前完成;在栅栏之后的任何变量读取都必须在栅栏之后开始。


缺点:每次获取 instance 都得拿锁,性能会降低。

 


方式3. 用双检锁实现线程安全

 

public class Singleton
{
    private static object s_lock = new object();

    private static Singleton instance = null;

    private Singleton() { }

    public Singleton GetInstance()
    {
        if (instance == null)
        {
            Monitor.Enter(s_lock);

            if (instance == null)
            {
                Singleton temp = new Singleton();
                Volatile.Write(ref instance, temp);
            }
        }

        return instance;
    }
}

> 《Java 双检锁问题》

 

> 为什么用 Volatile.Write 而不是 instance = new Singleton() ?

如果用 instance = new Singleton(),编译器可能先为 Singleton 分配内存,将引用赋给 instance,再调用构造器。这样可能在调用构造器完成之前,另一个线程调用了 GetInstance 并使用这个未构造完成的 Singleton 对象。
Volatile.Write 保证 temp 中的引用只有在构造器结束后才赋给 instance。

 


方式4. 不用锁的线程安全、非延迟创建

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

    private Singleton() { }

    public static Singleton GetInstance()
    {
        return instance;
    }
}

缺点:首次访问类的任何成员都会调用类型构造器,从而创建实例。

 

 


方式5. 延迟创建

 

public class Singleton
{
    private Singleton() { }

    public static Singleton GetInstance()
    {
        return Nested.instance;
    }

    private class Nested
    {
        internal static readonly Singleton instance = new Singleton();
    }
}



方式6. 用 Lazy<T>

public class Singleton
{
    private static Lazy<Singleton> instance
        = new Lazy<Singleton>(() => new Singleton(), true);

    private Singleton() { }

    public Singleton GetInstance()
    {
        return instance;
    }
}

 

 

 

小结:

不要炫技!

延迟创建实例确实可以加快类的加载速度,但这只是转移了耗时的阶段。是快速启动更重要,还是后续快速获取实例更重要,这得看具体业务需求。而且实现延迟创建的代码一般都更复杂。

一般我用这种方式:

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

    private Singleton() { }

    public static Singleton GetInstance()
    {
        return instance;
    }
}

 

如果需要延迟创建就用方式6。

分享到:
评论

相关推荐

    C#设计模式-整理收藏(吕震宇 设计模式速成经典示例)

    创建型模式如单例模式、工厂方法模式、抽象工厂模式等,关注对象的创建过程,确保在需要时能正确创建对象,同时保持系统设计的灵活性。结构型模式包括适配器模式、装饰器模式、代理模式、桥接模式、组合模式、外观...

    C#设计模式(1,共2)

    创建型模式关注对象的创建过程,如单例模式(Singleton)、工厂模式(Factory Method)和抽象工厂模式(Abstract Factory),它们使得代码在创建对象时更具灵活性和可扩展性。结构型模式涉及如何组合现有的类和对象...

    C#设计模式资料整理

    2. 单例模式(Singleton Pattern):确保一个类只有一个实例,并提供一个全局访问点。在C#中,通常使用静态成员或者双重检查锁定来实现单例,以保证线程安全。 3. 建造者模式(Builder Pattern):用于复杂对象的...

    C#技巧精华整理 C#技巧精华整理

    - 了解并应用常见的设计模式,如工厂模式、单例模式、观察者模式等,以提升代码的可读性和可维护性。 最后,阅读提供的CHM文件(15100824887.CHM)和"安装帮助.txt"文档,它们可能包含更详细的C#技巧和教程,而...

    【超全整理】C#语法解析、设计模式和数据库实例

    在C#中,常见的设计模式有单例模式(确保一个类只有一个实例)、工厂模式(提供创建对象的接口)、观察者模式(定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖于它的对象都会得到通知并被自动更新)、...

    个人整理的C#教程知识手册

    C#中常见的设计模式有单例模式、工厂模式、观察者模式、装饰器模式等。理解并应用这些模式能提升代码质量,增强可维护性和扩展性。 CHM文件是Microsoft的帮助文件格式,集成了HTML文档和索引,方便用户查阅。这份...

    GOF设计模式C#加强版

    - **Singleton(单例模式)**:确保一个类只有一个实例,并提供一个全局访问点。该模式常用于控制资源访问,例如数据库连接或日志对象。 ##### 2. 结构型模式 结构型模式关注的是如何组合类或对象以形成更大的结构...

    C#面试题整理.zip

    7. **设计模式**:面试题可能涵盖常见的设计模式,如工厂模式、单例模式、观察者模式、装饰器模式、适配器模式等。设计模式是解决常见软件设计问题的最佳实践。 8. **数据结构与算法**:面试题可能会包括链表、树...

    2019年最新整理出的20 套 c# 项目(包含开发实例及源代码)

    9. 设计模式:如单例模式、工厂模式、观察者模式等,提升代码质量和可维护性。 10. 异常处理:学习如何捕获和处理程序运行时可能出现的错误。 11. XML和JSON:数据交换格式,用于前后端交互。 12. Unit Testing:...

    2018C#面试整理

    - **单例模式**:确保一个类只有一个实例,并提供一个全局访问点。 - **简单工厂模式**:提供创建对象的接口,但让子类决定实例化哪个类。 - **抽象工厂模式**:提供一个接口,用于创建一系列相关或相互依赖的对象,...

    C# .net面试题整理集合

    13. **设计模式**:常见的设计模式如单例、工厂、观察者、装饰器、策略和代理模式,以及何时适用这些模式。 14. **软件工程与项目管理**:理解敏捷开发、Scrum框架,以及代码版本控制工具如Git的使用。 15. **安全...

    C#学习资料 学习资料整理工具

    6. **设计模式**:学习常见的软件设计模式,如单例模式、工厂模式、观察者模式等,以提升代码的可维护性和可扩展性。 7. **最佳实践**:涵盖编码规范、异常处理、性能优化、测试和调试等方面的建议,帮助开发者养成...

    C#常用类整理 都是工作中用到的

    11. **设计模式**: 在实际开发中,常用的设计模式如单例模式(Singleton)、工厂模式(Factory)、观察者模式(Observer)等,可以提高代码的可维护性和扩展性。 12. **反射(Reflection)**: 允许运行时动态地获取...

    51个c#-小程序例子精心整理的参考资料.rar

    12. **设计模式**:C#小程序可能包含了一些常见的设计模式应用,如工厂模式、单例模式、观察者模式等,这些都是软件设计的重要原则。 通过这些C#小程序实例,你可以逐步掌握C#编程的核心技术和最佳实践。同时,阅读...

    C#面试问题大全(最新整理)

    9. **设计模式**:工厂模式、单例模式、装饰器模式等常见设计模式及其在C#中的应用。 10. **单元测试与持续集成**:使用NUnit、MSTest等进行测试,以及Jenkins、Travis CI等工具进行持续集成。 以上只是C#面试问题...

    c# .net 面试题整理

    - 工厂模式、单例模式、观察者模式、装饰器模式等常见设计模式的实现和应用。 8. **LINQ(Language Integrated Query)** - LINQ的基本语法,如何使用LINQ查询数据。 - LINQ to Objects、LINQ to XML、LINQ to ...

    整理历届的经典C#面试题

    12. **设计模式**:了解常用的设计模式,如工厂模式、单例模式、观察者模式、装饰器模式等,以及如何在C#中实现它们。 13. **.NET框架与库**:了解ASP.NET、WPF、WinForms等.NET框架,以及System.IO、System.Net、...

    南京C#面试题目集合

    - 工厂模式、单例模式、观察者模式等常见设计模式的理解和实现。 - 面向接口编程:如何利用接口实现松耦合和可扩展性。 6. 数据库: - SQL语言:掌握基本的SQL查询、更新、删除和插入操作。 - ORM(Object-...

    C#类库,工具库大全

    2. **设计模式实现**:一些常见的设计模式,如工厂模式、单例模式、装饰器模式等,可能已经被封装成可复用的类库。 3. **数据访问层**:数据库操作相关的类库,如数据库连接池、SQL语句构建器、ORM工具等,简化了与...

Global site tag (gtag.js) - Google Analytics