iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C#实现单例模式的6种方法小结
  • 328
分享到

C#实现单例模式的6种方法小结

2024-04-02 19:04:59 328人浏览 薄情痞子
摘要

目录介绍Version 1 - 非线程安全Version 2 - 简单的线程安全Version 3 - Double-check locking的线程安全Version 4 - 不完

介绍

单例模式是软件工程学中最富盛名的设计模式之一。从本质上看,单例模式只允许被其自身实例化一次,且向外部提供了一个访问该实例的接口。通常来说,单例对象进行实例化时一般不带参数,因为如果不同的实例化请求传递的参数不同的话会导致问题的产生。(若多个请求都是传递的同样的参数的话,工厂模式更应该被考虑)

C#中实现单例有很多种方法,本文将按顺序介绍非线程安全、完全懒汉式、线程安全和低/高性能集中版本。

在所有的实现版本中,都有以下几个共同点:

  • 唯一的、私有的且无参的构造函数,这样不允许外部类进行实例化;

  • 类是密封的,尽管这不是强制的,但是严格来讲从上一点来看密封类能有助于JIT的优化

  • 一个静态变量应该指向类的唯一实例;

  • 一个公共的静态变量用于获得这个类的唯一实例(如果需要,应该创建它);

需要注意的是,本文中所有的例子中都是用一个 public static Instance的变量来访问单例类实例,要将其转换成公共函数是很容易的,但是这样并不会带来效率和线程安全上的提升。

Version 1 - 非线程安全

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

该版本在多线程下是不安全的,会创建多个实例,请不要在生产环境中使用!

因为如果两个线程同时运行到if(instance==null)判断时,就会创建两个实例,这是违背单例模式的初衷的。实际上在后面那个线程进行判断是已经生成了一个实例,但是对于不同的线程来说除非进行了线程间的通信,否则它是不知道的。

Version 2 - 简单的线程安全

public sealed class Singleton2
{
    private static Singleton2 instance = null;
    private static readonly object obj = new object();
    private Singleton2() { }
    public Singleton2 Instance
    {
        get
        {
            lock (obj)
            {
                if (instance == null)
                {
                    instance = new Singleton2();
                }
                return instance;
            }
        }
    }
}

该版本是线程安全的。通过对一个过线程共享的对象进行加锁操作,保证了在同一时刻只有一个线程在执行lock{}里的代码。当第一个线程在进行instance判断或创建时,后续线程必须等待直到前一线程执行完毕,因此保证了只有第一个线程能够创建instance实例。

但不幸的是,因为每次对instance的请求都会进行lock操作,其性能是不佳的。

需要注意的是,这里使用了一个private static object变量进行锁定,这是因为当如果对一个外部类可以访问的对象进行锁定时会导致性能低下甚至死锁。因此通常来说为了保证线程安全,进行加锁的对象应该是private的。

Version 3 - Double-check locking的线程安全

public sealed class Singleton3
{
    private static Singleton3 instance = null;
    private static object obj = new object();
    private Singleton3() { }
    public static Singleton3 Instance
    {
        get
        {
            if (instance == null)
            {
                lock (obj)
                {
                    if (instance == null)
                    {
                        instance = new Singleton3();
                    }
                }
            }
            return instance;
        }
    }
}

该版本中试图去避免每次访问都进行加锁操作并实现线程安全。然后,这段代码对Java不起作用,因Java的内存模型不能保证在构造函数一定在其他对象引用instance之前完成。还有重要的一点,它不如后面的实现方式。

Version 4 - 不完全懒汉式,但不加锁的线程安全

public sealed class Singleton4
{
    private static readonly Singleton4 instance = new Singleton4();
    /// <summary>
    /// 显式的静态构造函数用来告诉C#编译器在其内容实例化之前不要标记其类型
    /// </summary>
    static Singleton4() { }
    private Singleton4() { }
    public static Singleton4 Instance { get { return instance; } }
}

这个版本是的实现非常的简单,但是却又是线程安全的。C#的静态构造函数只有在当其类的实例被创建或者有静态成员被引用时执行,在整个应用程序域中只会被执行一次。使用当前方式明显比前面版本中进行额外的判断要快。

当然这个版本也存在一些瑕疵:

  • 不是真正意义上的懒汉模式(需要的时候才创建实例),若单例类还存在其他静态成员,当其他类第一次引用这些成员时便会创建该instance。下个版本实现会修正这个问题;

  • 只有.NET中才具有beforefieldinit特性,即懒汉式实现。且在.Net 1.1以前的编译器不支持,不过这个现在来看问题不大;

所有版本中,只有这里将instance设置成了readonly,这不仅保证了代码的高校且显得十分短小。

Version 5 - 完全懒汉实例化

public sealed class Singleton5
{
    private Singleton5() { }
    public static Singleton5 Instance { get { return Nested.instance; } }
    private class Nested
    {
        static Nested() { }
        internal static readonly Singleton5 instance = new Singleton5();
    }
}

该版本看起来稍微复杂难懂,其实只是在写法上实现了上一版本的瑕疵,通过内嵌类的方式先实现了只有在真正应用Instance时才进行实例化。其性能表现与上一版本无异。

Version 6 - 使用.NET 4 Lazy type 特性

public sealed class Singleton6
{
    private static readonly Lazy<Singleton6> lazy =
           new Lazy<Singleton6>(()=> new Singleton6());
    public static Singleton6 Instance { get { return lazy.Value; } }
    private Singleton6() { }
}

如果你使用的是.NET 4或其以上版本,可以使用System.Lazy type来实现完全懒汉式。其代码看起来也很简洁且性能表现也很好。

性能 VS 懒汉式

一般情况下,我们并不需要实现完全懒汉式,除非你的构造初始化执行了某些费时的工作。因此一般的,我们使用显式的静态构造函数就能够适用。

本文翻译自Implementing the Singleton Pattern in C#

Exception

有时候在进行构造函数初始化时可能 会抛出异常,但这对整个应用程序来说不应该是致命的,所以可能的情况下,你应该自己处理这种异常情况。

总结

上述提供的几种实现方法中,一般情况下提倡使用Version 4,除非遇到有时早于单列类实例化时就引用了其他静态成员。这种情况下,Version 2一旦被考虑,虽然它看起来会因加锁耗时,但是其实运行起来并没有你想的那么慢,关键是你很容易写对它。显然Version 1你永远都不应该考虑,Version 3在与Version 5的对比下也是不在考虑范围之内的。

到此这篇关于C#实现单例模式的6种方法的文章就介绍到这了,更多相关C#单例模式内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C#实现单例模式的6种方法小结

本文链接: https://www.lsjlt.com/news/166780.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C#实现单例模式的6种方法小结
    目录介绍Version 1 - 非线程安全Version 2 - 简单的线程安全Version 3 - Double-check locking的线程安全Version 4 - 不完...
    99+
    2024-04-02
  • Java单例模式的6种实现方式详解
    目录为什么使用单例模式使用单例模式需要注意的关键点单例模式的几种写法1. 饿汉式2. 懒汉式3. DCL(Double CheckLock)实现单例4. 静态内部类5...
    99+
    2024-04-02
  • JS实现单例模式的6种方案汇总
    前言 今天在复习设计模式中的-创建型模式,发现JS实现单例模式的方案有很多种,稍加总结了一下,列出了如下的6种方式与大家分享 大体上将内容分为了ES5(Function)与ES6(C...
    99+
    2024-04-02
  • C#实现单例模式的多种方式
    什么是单例模式 这里我就不做过多的解释了, 毕竟关于Singleton的资料实在是太多太多了。点击这里 简单的思路就是, 创建对象单例的动作转移到另外的行为上面, 利用一个行为去创建...
    99+
    2024-04-02
  • C++单例模式的几种实现方法详解
    目录局部静态变量方式静态成员变量指针方式智能指针方式辅助类智能指针单例模式通用的单例模板类总结局部静态变量方式 //通过静态成员变量实现单例 //懒汉式 class Single2 ...
    99+
    2024-04-02
  • C++实现单例模式的方法
    目录饿汉模式懒汉模式锁 + 智能指针局部静态变量总结 饿汉模式 类实例化就会占用内存,浪费资源,效率高,不存在线程安全问题。 class Singleton{ Singl...
    99+
    2024-04-02
  • Python实现单例模式的五种写法总结
    目录使用模块使用装饰器基于 __new__ 方法实现基于 metaclass 方式实现单例模式(Singleton Pattern) 是一种常用的软件设计模式,该模式的主要目的是确保...
    99+
    2024-04-02
  • Android 单例模式的四种实现方式
    目录一.饿汉式二.懒汉式三.双重检查加锁方式四.静态内部类方式总结一.饿汉式 public class SingletionStarving { private sta...
    99+
    2024-04-02
  • Java单例模式的五种实现方式
    目录前言饿汉单例懒汉单例非线程安全的懒汉单例加同步锁的懒汉单例双重检验懒汉单例静态内部类静态内部类为什么是线程安全总结前言 单例模式(Singleton Pattern)是 Java...
    99+
    2024-04-02
  • Java实现单例模式的五种方法介绍
    目录饿汉式懒汉式双重检查锁静态内部类内部枚举类实现饿汉式 立即加载 防止new对象,构造私有,写一个公共的方法返回对象 占用空间,线程安全 public class Singleto...
    99+
    2023-01-31
    Java单例模式 Java单例模式实现方式
  • 简单总结单例模式的4种写法
    目录一、单例模式二、写法三、饿汉式四、懒汉式五、内部类六、枚举七、结论一、单例模式 属于创建者模式的一种, 单例模式的目的是使该类只有一个实例,同一个类的不同对象有不同的hashCo...
    99+
    2024-04-02
  • C++实现单例模式的方法是什么
    这篇文章将为大家详细讲解有关C++实现单例模式的方法是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。饿汉模式类实例化就会占用内存,浪费资源,效率高,不存在线程安全问题。class&nbs...
    99+
    2023-06-22
  • C#多态的三种实现方式(小结)
    C#实现多态主要有3种方法,虚方法,抽象类,接口 1 虚方法 在父类的方法前面加关键字virtual, 子类重写该方法时在方法名前面加上override关键字,例如下面的Perso...
    99+
    2024-04-02
  • JS实现单例模式的N种方案
    目录JS实现单例模式的多种方案单例模式的概念方式1方式2方式3方式4方式5方式6JS实现单例模式的多种方案 ,本文稍加总结,列出了6种方式与大家分享,大体上将内容分为了ES5(Fun...
    99+
    2024-04-02
  • Python实现单例模式的四种方式详解
    简介:单例模式可以保证一个类仅有一个实例,并提供一个访问它的全局访问点。适用性于当类只能有一个实例而且客户可以从一个众所周知的访问点访问它,例如访问数据库、MQ等。 实现方式: 1、...
    99+
    2024-04-02
  • c++单例模式的实现方式有哪些
    在C++中,可以通过以下几种方式来实现单例模式: 饿汉式单例模式(Eager Initialization): 在类定义中静态地创...
    99+
    2024-02-29
    c++
  • Python 中用多种方式实现单例模式
    目录使用模块使用装饰器使用类基于 __new__ 方法实现基于 metaclass 方式实现单例模式(Singleton Pattern) 是一种常用的...
    99+
    2022-11-16
    Python实现单例模式 Python单例模式
  • JS中的6种打断点的方式实例总结
    目录前言普通断点条件断点DOM 断点URL 断点Event Listener 断点异常断点总结前言 Debugger 是前端开发很重要的一个工具,它可以在我们关心的代码处断住,通过单...
    99+
    2024-04-02
  • Python中单例模式的实现方法
    单例 — 让 类 创建的对象,在系统中 只有唯一的一个实例; 1)、定义一个类属性,初始值是 None ,用于记录 单例对象的引用;2)、重写 new 方法;3)、如果 ...
    99+
    2024-04-02
  • C++中有哪些实现单例模式的方式
    这篇文章将为大家详细讲解有关C++中有哪些实现单例模式的方式,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。C++单例模式有许多种实现方法,在C++中,甚至可以直接用一个全局变量做到这一点,但...
    99+
    2023-06-17
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作