c#中单例模式详解

这篇具有很好参考价值的文章主要介绍了c#中单例模式详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

基础介绍:

 确保一个类只有一个实例,并提供一个全局访问点。

  适用于需要频繁实例化然后销毁的对象,创建对象消耗资源过多,但又经常用到的对象,频繁访问数据库或文件的对象。

  其本质就是保证在整个应用程序生命周期中,任何一个时刻,单例类的实例都只存在一个

  • 特性和功能:确保一个类只有一个实例,并提供一个全局访问点。
  • 使用环境:当类只需要一个实例,且易于访问,且实例应在整个应用程序中共享时。
  • 注意事项:需要注意线程安全问题。
  • 优点:可以确保一个类只有一个实例,减少了内存开销。
  • 缺点:没有接口,扩展困难。  

应用场景:

  单例模式通常适用于在整个应用程序中只需要一个实例化对象的场景,以确保资源的高效利用和应用程序的稳定性。(共享资源)

  资源共享的情况下,避免由于资源操作时导致的性能或损耗等。

  控制资源的情况下,方便资源之间的互相通信。如线程池等。

  • 日志系统:在应用程序中,通常只需要一个日志系统,以避免在多个地方创建多个日志对象。这一般是由于共享的日志文件一直处于打开状态,所以只能有一个实例去操作,否则内容不好追加也有可能造成资源占用加剧资源消耗。
  • 数据库连接池:在应用程序中,数据库连接池是一个非常重要的资源,单例模式可以确保在应用程序中只有一个数据库连接池实例,避免资源浪费。主要是节省打开或者关闭数据库连接所引起的效率损耗,因为何用单例模式来维护,就可以大大降低这种损耗。
  • 配置文件管理器:在应用程序中,通常只需要一个配置文件管理器来管理应用程序的配置文件,单例模式可以确保在整个应用程序中只有一个配置文件管理器实例。这个是由于配置文件是共享的资源。
  • 缓存系统:在应用程序中,缓存系统是一个重要的组件,单例模式可以确保在整个应用程序中只有一个缓存实例,以提高应用程序的性能。
  • 网站在线人数统计:其实就是全局计数器,也就是说所有用户在相同的时刻获取到的在线人数数量都是一致的。
  • GUI组件:在图形用户界面(GUI)开发中,单例模式可以确保在整个应用程序中只有一个GUI组件实例,以确保用户界面的一致性和稳定性。

创建方式:

  饿汉式:类加载就会导致该单实例对象被创建。(静态变量方式、静态代码块方式)

  懒汉式:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建。(线程不安全型、线程安全型、双重检查锁)

 

  1. 懒汉式---非线程安全型

     1 public class Singleton
     2     {
     3         //定义一个私有的静态全局变量来保存该类的唯一实例
     4         private static Singleton singleton;
     5 
     6         /// <summary>
     7         /// 构造函数
     8         /// </summary>
     9         private Singleton()
    10         {
    11             //必须是私有的构造函数,这样就可以保证该类无法通过new来创建该类的实例。
    12             //想要使用该类只能通过唯一访问点GetInstance()。
    13         }
    14 
    15         /// <summary>
    16         /// 全局访问点
    17         /// 设置为静态方法则可在外边无需创建该类的实例就可调用该方法
    18         /// </summary>
    19         /// <returns></returns>
    20         public static Singleton GetInstance()
    21         {
    22             if (singleton == null)
    23             {
    24                 singleton = new Singleton();
    25             }
    26             return singleton;
    27         }
    28     }

    上面的代码中,由于构造函数被设置为 private 了,无法再在 Singleton 类的外部使用 new 来实例化一个实例,只能通过访问 GetInstance()来访问 Singleton 类。

    GetInstance()通过如下方式保证该 Singleton 只存在一个实例:

    首先这个 Singleton 类会在在第一次调用 GetInstance()时创建一个实例(第24行),并将这个实例的引用封装在自身类中的静态全局变量singleton(第4行)

    然后以后调用 GetInstance()时就会判断这个 Singleton 是否存在一个实例了(第22行),如果存在,则不会再创建实例。

    这样就实现了懒加载的效果。但是,如果是多线程环境,会出现线程安全问题。

    比如多个线程同时执行GetInstance()方法时都走到了第22行,这个时候一个线程进入 if 判断语句后但还没有实例化 Singleton 时,第二个线程到达,此时 singleton 还是为 null

    如此会造成多个线程都会进入 if 执行代码块中即都会执行第24行,这样的话,就会创建多个实例违背了单里模式,因此引出了实例2线程安全型。

     

  2. 懒汉式---线程安全型

     1 public class Singleton
     2     {
     3         //定义一个私有的静态全局变量来保存该类的唯一实例
     4         private static Singleton singleton;
     5 
     6         //线程锁
     7         private static readonly object _Object = new object();
     8 
     9         /// <summary>
    10         /// 构造函数
    11         /// </summary>
    12         private Singleton()
    13         {
    14             //必须是私有的构造函数,这样就可以保证该类无法通过new来创建该类的实例。
    15             //想要使用该类只能通过唯一访问点GetInstance()。
    16         }
    17 
    18         /// <summary>
    19         /// 全局访问点
    20         /// 设置为静态方法则可在外边无需创建该类的实例就可调用该方法
    21         /// </summary>
    22         /// <returns></returns>
    23         public static Singleton GetInstance()
    24         {
    25             lock (_Object)
    26             {
    27                 if (singleton == null)
    28                 {
    29                     singleton = new Singleton();
    30                 }
    31             }
    32             return singleton;
    33         }
    34     }

    相比实例1中可以看到在类中有定义了一个静态的只读对象  _Object(第7行),该对象主要是提供给lock 关键字使用。

    lock关键字参数必须为基于引用类型的对象,该对象用来定义锁的范围。

    当多个线程同时进入GetInstance()方法时,由于存在锁机制,当一个线程进入lock代码块时,其余线程会在lock语句的外部等待。

    当第一个线程执行完第29行创建对象实例后,便会退出锁定区域,这个时候singleton变量已经不为null了。

    所以余下线程再次进入lock代码块时,由于第27行的原因则不会再次创建对象的实例。

    但这里就涉及一个性能问题了,每一次有线程进入 GetInstance()时,均会执行锁定操作来实现线程同步,这是非常耗费性能的。

    解决这个问题也很简单,进行双重检查锁定判断即实例3。

     

  3. 懒汉式---双重检查锁

     1 public class Singleton
     2     {
     3         //定义一个私有的静态全局变量来保存该类的唯一实例
     4         private static Singleton singleton;
     5 
     6         //线程锁
     7         private static readonly object _Object = new object();
     8 
     9         /// <summary>
    10         /// 构造函数
    11         /// </summary>
    12         private Singleton()
    13         {
    14             //必须是私有的构造函数,这样就可以保证该类无法通过new来创建该类的实例。
    15             //想要使用该类只能通过唯一访问点GetInstance()。
    16         }
    17 
    18         /// <summary>
    19         /// 全局访问点
    20         /// 设置为静态方法则可在外边无需创建该类的实例就可调用该方法
    21         /// </summary>
    22         /// <returns></returns>
    23         public static Singleton GetInstance()
    24         {
    25             if (singleton == null)//第一重
    26             {
    27                 lock (_Object)
    28                 {
    29                     if (singleton == null)//第二重
    30                     {
    31                         singleton = new Singleton();
    32                     }
    33                 }
    34             }
    35             return singleton;
    36         }
    37     }

    相比实例2来看,只是增加了第25行。

    在多线程中,当第一个线程创建完对象的实例后,singleton变量已经不为null了。之后再访问GetInstance()方法时,将不会再进行lock等待。

    如果没有这行的情况下,每次多线程同时进入GetInstance()方法时,多余的线程都会进入lock进行等待。这是非常耗费性能的。

    相比调用GetInstance()方法来作为全局访问点还有另外一种写法:

     1  public class Singleton
     2     {
     3         private static Singleton instance;
     4 
     5         private Singleton() { }
     6 
     7         public static Singleton Instance
     8         {
     9             get
    10             {
    11                 if (instance == null)
    12                 {
    13                     instance = new Singleton();
    14                 }
    15                 return instance;
    16             }
    17         }
    18     }

    前三个实例在客户端调用:Singleton singletonOne = Singleton.GetInstance();

    后一种则可以直接:Singleton.Instance进行使用。

     

  4. 饿汉式

     1 public sealed class Singleton
     2     {
     3         //定义一个私有静态的只读的全局变量
     4         private static readonly Singleton singleton = new Singleton();
     5 
     6         /// <summary>
     7         /// 构造函数
     8         /// </summary>
     9         private Singleton()
    10         {
    11             //必须是私有的构造函数,这样就可以保证该类无法通过new来创建该类的实例。
    12             //想要使用该类只能通过唯一访问点GetInstance()。
    13         }
    14 
    15         /// <summary>
    16         /// 全局访问点
    17         /// 设置为静态方法则可在外边无需创建该类的实例就可调用该方法
    18         /// </summary>
    19         /// <returns></returns>
    20         public static Singleton GetInstance()
    21         {
    22             return singleton;
    23         }
    24     }

    在c#中使用静态初始化时无需显示地编写线程安全代码,C# 与 CLR 会自动解决前面提到的懒汉式单例类时出现的多线程同步问题。

    当整个类被加载的时候,就会自行初始化 singleton 这个静态只读变量。

    而非在第一次调用 GetInstance()时再来实例化单例类的唯一实例,所以这就是一种饿汉式的单例类。

总结:

  Singleton(单例):在单例类的内部实现只生成一个实例,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。

  (1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如日志文件,应用配置。

  (2)控制资源的情况下,方便资源之间的互相通信。如线程池等。

 

 

 

  

  文章来源地址https://www.toymoban.com/news/detail-738482.html

到了这里,关于c#中单例模式详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Unity程序技巧】Unity中单例模式管理器

    👨‍💻个人主页 :@元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 收录于专栏 :Unity基础实战 菜鸟教程 “单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一

    2024年02月08日
    浏览(29)
  • Java中单例(单态、原子)设计模式(饿汉式/懒汉式)

    先看文章目录,大致了解知识点结构,直接点击文章目录可以跳转到文章指定位置。 设计模式就是设计出来的固定问题的解决方法,描述了在软件设计过程中的一些不断重复发生的问题和解决方案。遇到类似问题的时候可以直接使用现成的模式方案。 ①单例模式中一个类只

    2024年02月04日
    浏览(28)
  • 【C#】五种单例模式详解

    饿汉模式、懒汉模式、双重锁懒汉模式、静态内部类模式、枚举模式。 public class SingleTon1 { private static SingleTon1 instance = new SingleTon1(); } 饿汉式,名字就能看出来,很饿,所以实例在初始化的时候就已经建好了。优点是没有线程安全的问题,缺点是浪费内存空间。 public class S

    2024年02月16日
    浏览(43)
  • [设计模式Java实现附plantuml源码~创建型] 确保对象的唯一性~单例模式

    前言: 为什么之前写过Golang 版的设计模式,还在重新写 Java 版? 答:因为对于我而言,当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言,更适合用于学习设计模式。 为什么类图要附上uml 因为很多人学习有做笔记的习惯,如果单纯的只是放一张图片,那

    2024年01月19日
    浏览(44)
  • C#设计模式之---单例模式

    单例模式,属于创建类型的一种常用的软件设计模式。通过单例模式的方法创建的类在当前进程中只有一个实例。 1)普通单例模式  2)懒汉式单例模式  3)饿汉式单例模式  或者  

    2024年02月14日
    浏览(36)
  • 单例模式【C#】

    只能生一个儿子。 文件操作只能一个单例去操作。 1static: static的特点是,不需要new就能使用。即使派生了,也是使用静态的对象。 静态方法,需要用类型去调用他。 2多线程:

    2024年02月05日
    浏览(28)
  • C#设计模式教程(4):单例模式

    单例模式(Singleton Pattern)是一种常用的设计模式,用于确保一个类只有一个实例,并提供一个访问它的全局访问点。在C#中实现单例模式通常有几种不同的方法,这里介绍几种典型的实现方式。 1. 懒汉式(线程不安全)

    2024年01月19日
    浏览(33)
  • C#设计模式之单例模式

    单例模式(Singleton)保证一个类仅有一个实例,并提供一个访问它的全局访问点。 单例模式的结构图如下所示: 对一些类来说,只有一个实例是很重要的。如何才能保证一个类只有一个实例并且这个实例易于被访问呢? 基于程序员之间的约定或是利用全局变量吗? 虽然这样

    2024年02月03日
    浏览(41)
  • c#设计模式-创建型模式 之 单例模式

    目录 前言: 优点: 缺点: 饿汉式(静态变量方式) 懒汉式(线程不安全) 懒汉式(双重检查锁定) 推荐方式Lazy 总结: 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供 了一种访问其唯一的对象的方式,可以直接访问,

    2024年02月13日
    浏览(29)
  • 一天一个设计模式---单例模式

    单例模式是一种创建型设计模式,其主要目的是确保一个类只有一个实例,并提供一个全局访问点。这意味着在应用程序中的任何地方,只能有一个实例存在,而不会创建多个相同类型的实例。 单例模式通常包括以下几个要素: 私有构造函数(Private Constructor): 单例类的构

    2024年02月02日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包