博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C#设计模式--单例模式
阅读量:5218 次
发布时间:2019-06-14

本文共 3965 字,大约阅读时间需要 13 分钟。

单例模式(也叫单件模式)的作用就是保证在整个应用程序的生命周期中,任何一个时刻,单例类的实例都只存在一个(当然也可以不存在)。

下面来看单例模式的结构图:

从上面的类图中可以看出单例模式的特点:

  1. 在单例类中有一个构造函数 Singleton ,但是这个构造函数却是私有的
  2. 公开了一个 GetInstance()方法

通过上面的类图不难看出单例模式的特点,从而也可以给出单例模式的定义:

单例模式保证一个类仅有一个实例,同时这个类还必须提供一个访问该类的全局访问点。

1.最基本的单例:

namespace Singleton {     public class Singleton     {         //定义一个私有的静态全局变量来保存该类的唯一实例         private static Singleton singleton;        ///          /// 构造函数必须是私有的         /// 这样在外部便无法使用 new 来创建该类的实例         ///          private Singleton()         {         }       ///          /// 定义一个全局访问点         /// 设置为静态方法         /// 则在类的外部便无需实例化就可以调用该方法         ///          /// 
public static Singleton GetInstance() { //这里可以保证只实例化一次 //即在第一次调用时实例化 //以后调用便不会再实例化 if (singleton == null) { singleton = new Singleton(); } return singleton; } } }

 

2.线程安全单例

namespace Singleton {     public class Singleton     {         //定义一个私有的静态全局变量来保存该类的唯一实例         private static Singleton singleton;        //定义一个只读静态对象         //且这个对象是在程序运行时创建的         private static readonly object syncObject = new object();        ///          /// 构造函数必须是私有的         /// 这样在外部便无法使用 new 来创建该类的实例         ///         private Singleton()        {       }        ///          /// 定义一个全局访问点         /// 设置为静态方法         /// 则在类的外部便无需实例化就可以调用该方法         ///          /// 
public static Singleton GetInstance() { //这里可以保证只实例化一次 //即在第一次调用时实例化 //以后调用便不会再实例化 //第一重 singleton == null if (singleton == null) { lock (syncObject) { //第二重 singleton == null if (singleton == null) { singleton = new Singleton(); } } } return singleton; } } }
  • 为何要使用双重检查锁定呢?

考虑这样一种情况,就是有两个线程同时到达,即同时调用 GetInstance(),

此时由于 singleton == null ,所以很明显,两个线程都可以通过第一重的 singleton == null ,

进入第一重 if 语句后,由于存在锁机制,所以会有一个线程进入 lock 语句并进入第二重 singleton == null ,

而另外的一个线程则会在 lock 语句的外面等待。

而当第一个线程执行完 new  Singleton()语句后,便会退出锁定区域,此时,第二个线程便可以进入 lock 语句块,

此时,如果没有第二重 singleton == null 的话,那么第二个线程还是可以调用 new  Singleton()语句,

这样第二个线程也会创建一个 Singleton 实例,这样也还是违背了单例模式的初衷的,

所以这里必须要使用双重检查锁定

 

  • 其实在没有第一重 singleton == null 的情况下,也是可以实现单例模式的,那么为什么需要第一重 singleton == null 呢?

这里就涉及一个性能问题了,因为对于单例模式的话,new Singleton()只需要执行一次就 OK 了,

而如果没有第一重 singleton == null 的话,每一次有线程进入 GetInstance()时,均会执行锁定操作来实现线程同步,

这是非常耗费性能的,而如果我加上第一重 singleton == null 的话,

那么就只有在第一次,也就是 singleton ==null 成立时的情况下执行一次锁定以实现线程同步,

而以后的话,便只要直接返回 Singleton 实例就 OK 了而根本无需再进入 lock 语句块了,这样就可以解决由线程同步带来的性能问题了。

好,关于多线程下单例模式的实现的介绍就到这里了,但是,关于单例模式的介绍还没完。

 

 

下面将要介绍的是懒汉式单例和饿汉式单例

1.懒汉式单例

何为懒汉式单例呢,可以这样理解,单例模式呢,其在整个应用程序的生命周期中只存在一个实例,

懒汉式呢,就是这个单例类的这个唯一实例是在第一次使用 GetInstance()时实例化的,

如果您不调用 GetInstance()的话,这个实例是不会存在的,即为 null

形象点说呢,就是你不去动它的话,它自己是不会实例化的,所以可以称之为懒汉。

其实呢,我前面在介绍单例模式的这几个 Demo 中都是使用的懒汉式单例

从前面的这个 GetInstance()中可以看出这个单例类的唯一实例是在第一次调用 GetInstance()时实例化的,

所以此为懒汉式单例。     

 

2.饿汉式单例

上面介绍了饿汉式单例,到这里来理解懒汉式单例的话,就容易多了,懒汉式单例由于人懒,

所以其自己是不会主动实例化单例类的唯一实例的,而饿汉式的话,则刚好相反,

其由于肚子饿了,所以到处找东西吃,人也变得主动了很多,所以根本就不需要别人来催他实例化单例类的为一实例,

其自己就会主动实例化单例类的这个唯一类。

在 C# 中,可以用特殊的方式实现饿汉式单例,即使用静态初始化来完成饿汉式单例模式

下面就来看一看饿汉式单例类

namespace Singleton {     public sealed class Singleton     {         private static readonly Singleton singleton = new Singleton();        private Singleton()         {         }        public static Singleton GetInstance()         {             return singleton;         }     } }

要先在这里提一下的是使用静态初始化的话,无需显示地编写线程安全代码,

C# 与 CLR 会自动解决前面提到的懒汉式单例类时出现的多线程同步问题。

上面的饿汉式单例类中可以看到,当整个类被加载的时候,就会自行初始化 singleton 这个静态只读变量。

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

 

好,到这里,就真正的把单例模式介绍完了,在此呢再总结一下单例类需要注意的几点:

一、单例模式是用来实现在整个程序中只有一个实例的。

二、单例类的构造函数必须为私有,同时单例类必须提供一个全局访问点。

三、单例模式在多线程下的同步问题和性能问题的解决。

四、懒汉式和饿汉式单例类。

五、C# 中使用静态初始化实现饿汉式单例类。

转载于:https://www.cnblogs.com/dxxzst/p/8444208.html

你可能感兴趣的文章
20.C++- &&,||逻辑重载操作符的缺陷、,逗号重载操作符的分析
查看>>
静态变量数组实现LRU算法
查看>>
在SQL中怎么把一列字符串拆分为多列
查看>>
中文系统 上传file的input显示英文
查看>>
css样式写一个三角形
查看>>
比callback更简洁的链式执行promise
查看>>
android permission
查看>>
javascript获取textarea中所选文本的开始位置、结束位置和选择的文本
查看>>
【译】在Asp.Net中操作PDF - iTextSharp - 使用字体
查看>>
事务备份还原分离附加
查看>>
JSch - Java实现的SFTP(文件上传详解篇)
查看>>
一些注意点
查看>>
.net 文本框只允许输入XX,(正则表达式)
查看>>
C#修饰符
查看>>
20.核心初始化之异常向量表
查看>>
[BSGS][哈希]luogu P3846 可爱的质数
查看>>
Python 第四十五章 MySQL 内容回顾
查看>>
iostat参数说明
查看>>
js 封装获取元素的第一个元素
查看>>
iOS 获取Home键指纹验证
查看>>