登录
/
注册
首页
论坛
其它
首页
科技
业界
安全
程序
广播
Follow
关于
签到
每天签到奖励2-10圆
导读
排行榜
TG频道
发帖说明
登录
/
注册
账号
自动登录
找回密码
密码
登录
立即注册
搜索
搜索
关闭
CSDN热搜
程序园
精品问答
技术交流
资源下载
本版
帖子
用户
软件
问答
教程
代码
写记录
VIP申请
VIP网盘
网盘
联系我们
发帖说明
每日签到
道具
勋章
任务
淘帖
动态
分享
留言板
导读
设置
我的收藏
退出
腾讯QQ
微信登录
返回列表
首页
›
业界区
›
业界
›
c#中单例模式详解
c#中单例模式详解
[ 复制链接 ]
娄静曼
2025-6-9 07:11:10
一、基础介绍:
确保一个类只有一个实例,并提供一个全局访问点。
适用于需要频繁实例化然后销毁的对象,创建对象消耗资源过多,但又经常用到的对象,频繁访问数据库或文件的对象。
其本质就是保证在整个应用程序的生命周期中,任何一个时刻,单例类的实例都只存在一个。
特性和功能:确保一个类只有一个实例,并提供一个全局访问点。
使用环境:当类只需要一个实例,且易于访问,且实例应在整个应用程序中共享时。
注意事项:需要注意线程安全问题。
优点:可以确保一个类只有一个实例,减少了内存开销。
缺点:没有接口,扩展困难。
二、应用场景:
单例模式通常适用于在整个应用程序中只需要一个实例化对象的场景,以确保资源的高效利用和应用程序的稳定性。(共享资源)
资源共享的情况下,避免由于资源操作时导致的性能或损耗等。
控制资源的情况下,方便资源之间的互相通信。如线程池等。
日志系统:在应用程序中,通常只需要一个日志系统,以避免在多个地方创建多个日志对象。这一般是由于共享的日志文件一直处于打开状态,所以只能有一个实例去操作,否则内容不好追加也有可能造成资源占用加剧资源消耗。
数据库连接池:在应用程序中,数据库连接池是一个非常重要的资源,单例模式可以确保在应用程序中只有一个数据库连接池实例,避免资源浪费。主要是节省打开或者关闭数据库连接所引起的效率损耗,因为何用单例模式来维护,就可以大大降低这种损耗。
配置文件管理器:在应用程序中,通常只需要一个配置文件管理器来管理应用程序的配置文件,单例模式可以确保在整个应用程序中只有一个配置文件管理器实例。这个是由于配置文件是共享的资源。
缓存系统:在应用程序中,缓存系统是一个重要的组件,单例模式可以确保在整个应用程序中只有一个缓存实例,以提高应用程序的性能。
网站在线人数统计:其实就是全局计数器,也就是说所有用户在相同的时刻获取到的在线人数数量都是一致的。
GUI组件:在图形用户界面(GUI)开发中,单例模式可以确保在整个应用程序中只有一个GUI组件实例,以确保用户界面的一致性和稳定性。
三、创建方式:
饿汉式:类加载就会导致该单实例对象被创建。(静态变量方式、静态代码块方式)
懒汉式:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建。(线程不安全型、线程安全型、双重检查锁)
懒汉式---非线程安全型
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线程安全型。
懒汉式---线程安全型
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。
懒汉式---双重检查锁
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进行使用。
饿汉式
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)控制资源的情况下,方便资源之间的互相通信。如线程池等。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
中单例
模式
详解
相关帖子
Kubernetes Service详解:实现服务发现与负载均衡
C# 弃元模式:从语法糖到性能利器的深度解析
PWA(渐进式网页应用)详解和应用场景(AI)
嵌入式固件升级框架详解与实战经验
三类代码协同模式,你要如何选?
最小二乘问题详解5:非线性最小二乘求解实例
Stimulsoft 报表脚本执行模式风险与防护建议
CRC32的直接和反转模式
freeswitch的proxy_media模式下video流的问题与修正
VTK开发笔记(五):示例Cone2,熟悉观察者模式,在Qt窗口中详解复现对应的Demo
vip免费申请,1年只需15美金$
回复
使用道具
举报
提升卡
置顶卡
沉默卡
喧嚣卡
变色卡
千斤顶
照妖镜
相关推荐
业界
Kubernetes Service详解:实现服务发现与负载均衡
1
733
骆贵
2025-10-09
业界
C# 弃元模式:从语法糖到性能利器的深度解析
1
54
南宫玉英
2025-10-10
业界
PWA(渐进式网页应用)详解和应用场景(AI)
0
280
醋辛
2025-10-10
业界
嵌入式固件升级框架详解与实战经验
0
215
尝琨
2025-10-10
安全
三类代码协同模式,你要如何选?
0
335
跟尴
2025-10-10
业界
最小二乘问题详解5:非线性最小二乘求解实例
0
681
赵淳美
2025-10-16
业界
Stimulsoft 报表脚本执行模式风险与防护建议
0
125
讣丢
2025-10-17
安全
CRC32的直接和反转模式
0
528
蒲善思
2025-10-17
业界
freeswitch的proxy_media模式下video流的问题与修正
0
937
唐茗
2025-10-17
业界
VTK开发笔记(五):示例Cone2,熟悉观察者模式,在Qt窗口中详解复现对应的Demo
0
5
顶豌
2025-10-20
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
|
立即注册
回复
本版积分规则
回帖并转播
回帖后跳转到最后一页
签约作者
程序园优秀签约作者
发帖
娄静曼
2025-6-9 07:11:10
关注
0
粉丝关注
23
主题发布
板块介绍填写区域,请于后台编辑
财富榜{圆}
anyue1937
9994893
dage888
999994
3934307807
992122
4
富账慕
9977
5
刎唇
9993
6
邹语彤
9976
7
二艰糖
9994
8
匝抽
9986
9
聚怪闩
9960
10
孙淼淼
9977
查看更多