c#设计模式之单例模式的实现方式
场景描述
单例模式对于我们来说一点也不模式,是一个常见的名称,单例模式在程序中的实际效果就是:确保一个程序中只有一个实例,并提供一个全局访问点,节省系统资源
单例模式无论是在实际开发中还是在软件应用中比较常见,比如,windows系统的任务管理器、IIS的HttpApplication、实际项目中的日志组件等等
实现方式
单例模式为了实现一个实例,那么只有不把实例创建暴露出去,只通过类本身来创建实例,为了实现效果,需要定义一个私有构造函数
单例模式实现方式有:饿汉式、懒汉式、双重验证式、静态内部类
下面分别对每一种实现方式做一个简单的实例,以及其优缺点
饿汉式
/// <summary> /// 创建一个 Singleton 类(饿汉式) /// 这种方式比较常用,但容易产生垃圾对象。 ///优点:没有加锁,执行效率会提高。 ///缺点:类加载时就初始化,浪费内存。 ///它基于 classloder 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化, ///虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, ///但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。 /// </summary> public class SingleObject { //创建 SingleObject 的一个对象 private static SingleObject instance = new SingleObject(); //让构造函数为 private,这样该类就不会被实例化 private SingleObject() { Console.WriteLine("我被创建了.饿汉式"); } //获取唯一可用的对象 public static SingleObject GetInstance() { return instance; } public void ShowMessage() { Console.WriteLine("Hello World.饿汉式"); } }
懒汉式
/// <summary> /// 创建一个 Singleton 类(懒汉式) /// 这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。 /// 优点:第一次调用才初始化,避免内存浪费。 /// 缺点:懒汉式在单个线程中没有问题,但多个线程同事访问的时候就可能同事创建多个实例,而且这多个实例不是同一个对象。 /// </summary> public class SingleObject1 { //创建 SingleObject 的一个对象 private static SingleObject1 instance; //让构造函数为 private,这样该类就不会被实例化 private SingleObject1() { } //获取唯一可用的对象 public static SingleObject1 GetInstance() { if (instance == null) { instance = new SingleObject1(); Console.WriteLine("我被创建了.懒汉式"); } return instance; } public void ShowMessage() { Console.WriteLine("Hello World.懒汉式"); } }
双重验证式
/// <summary> /// 创建一个 Singleton 类(双重验证) /// 这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。 /// 优点:第一次调用才初始化,避免内存浪费,线程安全。 /// 缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。 /// </summary> public class SingleObject2 { //创建 SingleObject 的一个对象 private static SingleObject2 instance; // 定义一个标识确保线程同步 private static readonly object locker = new object(); //让构造函数为 private,这样该类就不会被实例化 private SingleObject2() { } //获取唯一可用的对象 public static SingleObject2 GetInstance() { //// 如果为空,那么就加锁,创建实例 if (instance == null) { lock (locker) { //// 枷锁成功后,在做一次非空判断,避免在加锁期间以创建了实例而导致重复创建 if (instance == null) { instance = new SingleObject2(); Console.WriteLine("我被创建了.双重验证"); } } } return instance; } public void ShowMessage() { Console.WriteLine("Hello World.双重验证"); } }
静态内部类
/// <summary> /// 创建一个 Singleton 类(静态内部类) /// 这种方式不用加锁,在效率上和内存使用上都比较优秀 /// 克服了饿汉模式的不足饿汉模式执行效率高,由于在类加载的时候初始化导致内存浪费 /// </summary> public class SingletonStatic { /// <summary> /// 内部类 /// </summary> public class SingletonStaticInner { /// <summary> /// 当一个类有静态构造函数时,它的静态成员变量不会被beforefieldinit修饰 /// 就会确保在被引用的时候才会实例化,而不是程序启动的时候实例化 /// </summary> static SingletonStaticInner() { } /// <summary> /// 实例化 /// </summary> internal static SingletonStatic singletonStatic = new SingletonStatic(); } /// <summary> /// 私有构造函数 /// </summary> private SingletonStatic() { Console.WriteLine("我被创建了.静态内部类"); } /// <summary> /// 获取实例 /// </summary> /// <returns></returns> public static SingletonStatic GetInstance() { return SingletonStaticInner.singletonStatic; } public void ShowMessage() { Console.WriteLine("Hello World.静态内部类"); } }
每一种创建方式测试
创建一个控制台程序,通过多线程对每一种实现方式使用,查看其实例次数分析:
/* 介绍 意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。 主要解决:一个全局使用的类频繁地创建与销毁。 何时使用:当您想控制实例数目,节省系统资源的时候。 如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。 关键代码:构造函数是私有的。 应用实例: 典型的已有应用: 1、windows的任务管理器等 2、IIS的HttpApplication,所有的HttpModule都共享一个HttpApplication实例 在项目中的实际使用场景: 1、日志组件 2、多线程线程池管理 3、网站计数器 4、配置文件管理 */ class Program { static void Main(string[] args) { TaskFactory taskFactory = new TaskFactory(); List<Task> taskList = new List<Task>(); //// 测试--饿汉式 for (int i = 0; i < 5; i++) { taskList.Add(taskFactory.StartNew(() => { SingleObject.GetInstance(); })); } //// 测试--懒汉式 for (int i = 0; i < 5; i++) { taskList.Add(taskFactory.StartNew(() => { SingleObject1.GetInstance(); })); } //// 测试--双重验证 for (int i = 0; i < 5; i++) { taskList.Add(taskFactory.StartNew(() => { SingleObject2.GetInstance(); })); } //// 测试--静态内部类 for (int i = 0; i < 5; i++) { taskList.Add(taskFactory.StartNew(() => { SingletonStatic.GetInstance(); })); } Console.ReadLine(); } }
运行结果:
通过结果可以看出:懒汉式实际创建了2个实例,所以在多线程中,懒汉式有线程不安全问题
总结
根据单例模式是每一种实现方式对比分析,在实际使用过程中:
如果是单线程应用环境,建议可以采用懒汉模
如果是多线程应用环境,建议采用静态内部类方式
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。
栏 目:C#教程
下一篇:C#利用栈实现加减乘除运算
本文标题:c#设计模式之单例模式的实现方式
本文地址:https://www.xiuzhanwang.com/a1/C_jiaocheng/4618.html
您可能感兴趣的文章
- 01-10C#使用Dispose模式实现手动对资源的释放
- 01-10深入浅出23种设计模式
- 01-10Python设计模式编程中的备忘录模式与对象池模式示例
- 01-10详解C#的设计模式编程之抽象工厂模式的应用
- 01-10解析C#设计模式编程中的装饰者模式
- 01-10简单了解C#设计模式编程中的桥接模式
- 01-10C#编程中使用设计模式中的原型模式的实例讲解
- 01-10剖析设计模式编程中C#对于组合模式的运用
- 01-10实例解析C#设计模式编程中简单工厂模式的使用
- 01-10解析C#设计模式编程中适配器模式的实现
阅读排行
本栏相关
- 01-10C#通过反射获取当前工程中所有窗体并
- 01-10关于ASP网页无法打开的解决方案
- 01-10WinForm限制窗体不能移到屏幕外的方法
- 01-10WinForm绘制圆角的方法
- 01-10C#实现txt定位指定行完整实例
- 01-10WinForm实现仿视频 器左下角滚动新
- 01-10C#停止线程的方法
- 01-10C#实现清空回收站的方法
- 01-10C#通过重写Panel改变边框颜色与宽度的
- 01-10C#实现读取注册表监控当前操作系统已
随机阅读
- 08-05DEDE织梦data目录下的sessions文件夹有什
- 01-10使用C语言求解扑克牌的顺子及n个骰子
- 01-10C#中split用法实例总结
- 01-11ajax实现页面的局部加载
- 08-05dedecms(织梦)副栏目数量限制代码修改
- 08-05织梦dedecms什么时候用栏目交叉功能?
- 01-10SublimeText编译C开发环境设置
- 01-10delphi制作wav文件的方法
- 04-02jquery与jsp,用jquery
- 01-11Mac OSX 打开原生自带读写NTFS功能(图文