文章目录

  • 简介
  • 不安全线程的单例模式
  • 简单安全线程带锁
  • 双重检查 - 带锁
  • 安全初始化
  • 安全并且懒汉式静态初始化
  • 带泛型的懒汉式单例
  • 异常
  • 提高效率
  • 总结

简介

  单例模式是软件工程中广为人知的设计模式。单例模式就是指一个永远只能实例化一次。使用的方式是调用类里创建的静态方法。通常来说,单例模式创建的类,都是不带形参的 ,原因就是当创建多个实例的时候,如果参数不同的话(比如2个不同的重载构造函数),那么就会造成一些不必要的问题(如果相同的实例要被创建而且他们使用相同的参数的话,那么建议使用工厂模式),这篇文章的定位就是没有 任何的参数的情况下,通常情况下,单例模式是LAZY的,也就是说相当的容易创建。

  在C#中实现单例模式有很多种方式。我将在下面以上面的目录的形式呈现给大家,开始我会跟大家介绍最常用的单例模式的写法,这些写法的线程并不安全,然后会提到懒汉式写法(Lazy-Load),然后就是线程安全,最后会跟大家介绍一下提高效率的方式。

  所有的实现将会用通俗的语言来介绍,但是要注意以下:

  • 只有一个构造函数,而且这个构造函数是私有的,不带任何的参数的。这是为了防止其他的类实例化这个单例类(这也许违反了设计模式),注意这种方式也会阻止子类,如果单例能被子类实例化一次,那么也可以被子类实例化多次。如果单例的每个子类都可以创建实例的话,就违反了单例模式。如果你需要父类(基类)的单例的实现的话我觉得工厂模式是可以有用到的,但是具体的类型不会被知道直到运行时(CLR)开始。
  • 类是sealed的,也就是封闭的。这是没有必要的,严格意义上说,只是为了JIT提高效率。
  • 静态变量 ,类型被定义为这个单例类的一个引用。
  • 建立一个公共的而且静态的方法,返回值是这个单例类,如果有需要的话。

  注意所有的实现都是用一个公共的且静态的属性作为实例的入口。在所有的情况下属性可以方便的转换成方法,而且和线程安全或者效率不冲突。

第一个版本 -  非线程安全

// 不要用这种方式
public sealed class Singleton
{private static Singleton instance=null;private Singleton(){}public static Singleton Instance{get{if (instance==null){instance = new Singleton();}return instance;}}
}

  我要表明的是,上面的方法是非线程安全的,2个不同的线程可以同时进入这个方法,如果instance为空的并且这里返回真的情况下,都可以创建实例,这显然违反了单例模式,实际上,在测试以前,实例就已经有可能被创建了,但是内存模型不能保证这个实例能被其他的线程看到,除非合适的内存屏障已经被跨过了。

第二个版本 - 简单安全线程

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

  上述实现是线程安全的。这个线程在共享的object上取出了一把锁,然后在创建实例以前检查这个实例是否被创建了。这个保护了内存屏障问题(lock保证了所有的读取操作是在LOCK获得以后发生的,所有的unlock保证了所有的写操作在lock 释放以后发生的),这样就保证了一个线程只能创建一个实例(每次只有一个线程在这段代码中运行),不巧的是,性能上来说,锁变成了每次都必须的当这个实例被响应的时候。

  注意除了在锁当中锁住typeof(Singleton)这种类型的以外,我锁住了一个静态私有的变量,对于这个类来说。如果是锁 的一个对象的话,其他的类可以进入并且锁住(比如Type)这样会造成性能风险的问题甚至死锁。这是我的大体偏好 - 也许可能的话,只有锁住对象才能达到最终的目的,或者某些文章说锁是为了达到一些特别的目的。(比如等待或者脉冲一个队列)。通常来说这样的对象应该被设置成私有的。这样会让写线程安全更加的容易。

第三个版本 - 尝试线程安全(双重锁定)

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

  这个实现尝试了线程安全,当然并没必要每次都要取出lock,但是这种方式有如下4个缺点:

  • 这种方式JAVA中是无效的。也许你会认为我这是在说废话,但是我觉得这是值得你去了解的。JAVA内存模型中新对象的引用被分配到实例之前并不能保证构造函数完成初始化,JAVA 内存模型重新工作(在1.5版本中),但是双重检查锁依然是坏的,在不带volatile 的变量(比如C#)。
  • 不带任何的记忆屏障,在ECMA CLI规格中也是破碎的。也许在.NET 2.0以下是安全的,但是我更倾向于不依赖于哪些强类型的语义,特别的说,对于安全性来说这是值得怀疑的。如果把变量变成 volatile的是可以运行的,明确的内存屏障会进行响应,虽然后面有些情况专家都不能完全同意屏障是必须的。我打算尝试避免站在对的或者错误的立场上去回答这个问题!
  • 容易报错。这种模式要像上面一样的精确 - 任何的大的改动都会造成正确性和性能方面的冲击。
  • 依然没有后面说的那种写法好。

第四个版本 -  不完全lazy,但是线程安全且不用用锁

public sealed class Singleton
{private static readonly Singleton instance = new Singleton();// 显示的static 构造函数//没必要标记类型 - 在field初始化以前static Singleton(){}private Singleton(){}public static Singleton Instance{get{return instance;}}
}

未完待续,原文链接地址:

http://csharpindepth.com/Articles/General/Singleton.aspx#unsafe

转载于:https://www.cnblogs.com/kmsfan/p/4562323.html

C# 中实现单例模式相关推荐

  1. 【C++】C/C++ 中的单例模式

    目录 part 0:单例模式3种经典的实现方式 Meyer's Singleton Meyers Singleton版本二 Lazy Singleton Eager Singleton Testing ...

  2. python编程入门单例_常见的在Python中实现单例模式的三种方法

    单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源.如果希望在 ...

  3. Java中的单例模式

    2019独角兽企业重金招聘Python工程师标准>>> 最近网上查找资料做了一下总结,Java中的单例模式主要是有以下两种实现方式: 1.public class Singleton ...

  4. 在Java中实现单例模式的有效方法是什么? [关闭]

    在Java中实现单例模式的有效方法是什么? #1楼 我使用Spring框架来管理我的单身人士. 它不会强制类的"单一性"(如果涉及多个类加载器,您将无法真正做到),但是它提供了一种 ...

  5. java 单例模式打包jar_在 Spark 中实现单例模式的技巧

    单例模式是一种常用的设计模式,但是在集群模式下的 Spark 中使用单例模式会引发一些错误.我们用下面代码作例子,解读在 Spark 中使用单例模式遇到的问题. object Example{ var ...

  6. php应用数据库连接中的单例模式

    所谓的单例模式简而言之就是某个类在运行过程中只有一个实例,并且能够自行实例化并为整个系统的运行提供这个实例.在数据库连接中使用单例模式实例化数据库连接对象主要是可以避免重复的实例化对象而造成资源的浪费 ...

  7. java 多线程的单例模式,Java多线程中的单例模式两种实现方式

    Java多线程中的单例模式 一.在多线程环境下创建单例 方式一: package com.ietree.multithread.sync; public class Singletion { priv ...

  8. android studio列模式,在Android studio 中使用单例模式

    本篇简单介绍如何在Android studio中 使用单例模式和使用注意事项. 单例模式 为什么要使用单例模式? 有一些对象我们只需要一个,只需要一个线程池 .缓存或是只有一台打印机.机器人 .机器人 ...

  9. Go语言中的单例模式

    转载地址:https://mp.weixin.qq.com/s/JAlt0JQt8hkPCxYbmOMFJw Go语言中的单例模式 在过去的几年中,Go语言的发展是惊人的,并且吸引了很多由其他语言(P ...

最新文章

  1. 独家 | 一文带你盘点最新热门技术话题,技术圈潮人必读!
  2. 死机一个月后,31岁的哈勃望远镜又复活了
  3. IR2104s半桥驱动使用经验
  4. python软件怎么用-用Python如何打出你的第一个程序
  5. php 配置域名与端口号,lnmp 配置不同端口号的域名
  6. java9.0.1教学,零基础Java基础教程【9天入门】
  7. asp.net中有关URL的信息
  8. vue路由1.0_【Vue】路由
  9. 控制服务器系统设计,基于 DNS 技术的顶管机远程控制系统设计与实现
  10. win10系统怎么查看密钥?
  11. 终端应用安全之网络流量分析
  12. 抢票软件开发(二) 模拟登录
  13. windows下cfree5中%d输出浮点数的问题
  14. 网络安全人员经常使用的十大网站
  15. 奶制品生产与销售matlab,奶制品的生产与加工
  16. 论文复现:<Beyond Static Features for Temporally Consistent 3D Human Pose and Shape from a Video>
  17. Pyautogui 实现键盘鼠标动作
  18. 莫比乌斯反演公式推导
  19. 字王·百字工程·2016中秋纪念
  20. 着手去做吧,心中的想法总会是无限动力

热门文章

  1. New ADODB.Connection ADOX.Catalog 提示user-defined type not defined
  2. XXX管理平台系统——项目教训
  3. is 和 ==的区别
  4. C#并行开发_Thread/ThreadPool, Task/TaskFactory, Parallel
  5. java设计模式 工厂模式
  6. Lazy Load, 延迟加载图片的 jQuery 插件 - NeoEase
  7. S2S ×××如何穿越NAT
  8. 服务器架构之性能扩展-第七章(8)
  9. RBAC角色权限设计
  10. 中小型研发团队架构实践:高效率、低风险,一键发布并测试的持续集成工具Jenkins...