/// <summary>
/// 双检锁实现单例
/// </summary>
public sealed class SingletonDoubleCheck
{
//s_lock对象是实现线程安全所需要的,定义这个对象时,我们假设创建单例对象的代价高于创建一个System.Object对象
//并假设可能根本不需要创建单例对象,否则,更经济、更简单的做法是在一个类构造器中创建单例对象
private static Object s_lock = new Object(); //这个字段引用一个单例对象
private static SingletonDoubleCheck s_value = null; //私有构造器阻止这个类外部的任何代码创建实例
private SingletonDoubleCheck()
{ } //以下公共静态方法返回单例对象(如有必要就创建它)
public static SingletonDoubleCheck GetSingleton()
{
//如果单例对象已经创建,则直接返回它
if (s_value != null)
{
return s_value;
} //在指定对象上获取排他锁
Monitor.Enter(s_lock); //再次检查是否已经创建
//解决问题:若多个线程首次(单例对象还未创建)同时进入,此时,只有一个线程执行下面的代码(因为有Monitor),
//当该线程(第一个线程)创建完实例后,另一个线程(第二个线程)立即获得锁,也执行下面的代码,
//此时实例已经创建完成,后面的线程应该直接返回才对,因此再判断一次实例是否已经创建。
if (s_value == null)
{
//若仍未创建则创建它
SingletonDoubleCheck singleton = new SingletonDoubleCheck(); //将singleton给s_value
//下面的代码保证singleton中的引用只有在构造器结束执行之后才发布到s_value中
Volatile.Write(ref s_value, singleton); //注意:下面的写法是不牢靠的
//因为编译器可能会这样做:
//1.为SingletonDoubleCheck分配内存
//2.将引用发布到(赋给)s_value
//3.调用构造器
//假设在将引用发布给s_value之后,但在调用构造器之前,若有另一个线程调用了GetSingleton,
//此时s_value不为null,该线程会使用该对象,但该对象的构造器还没执行完成。
//s_value = new SingletonDoubleCheck();
} //释放指定对象上的排他锁
Monitor.Exit(s_lock); return s_value;
}
} /// <summary>
/// C#下简单的构造单例方法
/// CLR已保证了对类的构造是线程安全的,书写非常简便
/// 缺点也很明显,首次访问类的任何成员时都会调用类型构造器
/// 所以,如果该类定义了其它静态成员,就会在访问其它任何静态成员时创建该对象
/// </summary>
public sealed class SingletonSimple
{
private static SingletonSimple s_value = new SingletonSimple(); //私有构造器阻止这个类外部的任何代码创建实例
private SingletonSimple()
{ } //以下公共静态方法返回单例对象(如有必要就创建它)
public static SingletonSimple GetSingleton()
{
return s_value;
} //或
public static SingletonSimple SingletonInstance
{
get { return s_value; }
} //或
public static SingletonSimple Instance { get; } = new SingletonSimple();
} /// <summary>
/// 嵌套类实现单例
/// 如果多个线程同时调用GetSingleton,则可能创建多个SingletonNested对象
/// 但由于使用了Interlocked.CompareExchange,所以保证只会有一个引用被发布到s_value
/// 没有被固定下来的对象都会被垃圾回收
/// 该种方式不会阻塞线程
/// </summary>
public sealed class SingletonNested
{
private static SingletonNested s_value = null; //私有构造器阻止这个类外部的任何代码创建实例
private SingletonNested()
{ } //以下公共静态方法返回单例对象(如有必要就创建它)
public static SingletonNested GetSingleton()
{
//如果单例对象已经创建,则直接返回它
if (s_value != null)
{
return s_value;
} //创建一个新的单例对象,并把它固定下来(如果另一个线程还没有固定它的话)
SingletonNested singletonNested = new SingletonNested(); //比较两个指定的引用类型的实例 T 是否相等,如果相等,则替换第一个,并且返回s_value原始值
//s_value与null比较,如果相等则用singletonNested替换s_value,否则不替换
Interlocked.CompareExchange(ref s_value, singletonNested, null); //如果该线程竞争失败,则新建的第二个单实例对象会被垃圾回收 return s_value;
}
}

三种方式构建C#单例模式的更多相关文章

  1. 彻底了解构建 JSON 字符串的三种方式

    原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7701856.html 前言:JSON 是轻量级的数据交换格式,很常用,尤其是在使用 Ajax ...

  2. python实现单例模式的三种方式及相关知识解释

    python实现单例模式的三种方式及相关知识解释 模块模式 装饰器模式 父类重写new继承 单例模式作为最常用的设计模式,在面试中很可能遇到要求手写.从最近的学习python的经验而言,singlet ...

  3. Solon 开发,三、构建一个Bean的三种方式

    Solon 开发 一.注入或手动获取配置 二.注入或手动获取Bean 三.构建一个Bean的三种方式 四.Bean 扫描的三种方式 五.切面与环绕拦截 六.提取Bean的函数进行定制开发 七.自定义注 ...

  4. C#批量插入数据到Sqlserver中的三种方式

    本篇,我将来讲解一下在Sqlserver中批量插入数据. 先创建一个用来测试的数据库和表,为了让插入数据更快,表中主键采用的是GUID,表中没有创建任何索引.GUID必然是比自增长要快的,因为你生 成 ...

  5. PHP的学习--连接MySQL的三种方式

    记录一下PHP连接MySQL的三种方式. 先mock一下数据,可以执行一下sql. /*创建数据库*/ CREATE DATABASE IF NOT EXISTS `test`; /*选择数据库*/ ...

  6. php 链接mysql的三种方式对比

    PHP连接Mysql的三种方式: 1.原生的连接方式  原生的连接方式是面向过程的写法 <?php $host = 'localhost'; $database = 'test'; $usern ...

  7. dubbo服务运行的三种方式

    dubbo服务运行,也就是让生产服务的进程一直启动.如果生产者进程挂掉,也就不存在生产者,消费者不能进行消费. Dubbo服务运行的三种方式如下:1.使用Servlet容器运行(Tomcat.Jett ...

  8. python 全栈开发,Day94(Promise,箭头函数,Django REST framework,生成json数据三种方式,serializers,Postman使用,外部python脚本调用django)

    昨日内容回顾 1. 内容回顾 1. VueX VueX分三部分 1. state 2. mutations 3. actions 存放数据 修改数据的唯一方式 异步操作 修改state中数据的步骤: ...

  9. Spring MVC异常统一处理的三种方式

    Spring 统一异常处理有 3 种方式,分别为: 使用 @ ExceptionHandler 注解 实现 HandlerExceptionResolver 接口 使用 @controlleradvi ...

随机推荐

  1. 移动端自动化测试之android模拟器问题集合

    黑屏 在做移动端自动化测试过程中,android模拟器启动黑屏的问题一直困扰着我,网上找了许多方法尝试了都不能解决我的问题,最后重新安装了镜像文件,问题才得以解决,当然并不是网上的解决办法都是错的,只 ...

  2. js模板(template.js)实现页面动态渲染

    template.js是由纯JavaScript编写的第三方模板引擎.点击https://github.com/yanhaijing/template.js可进行下载. 在页头导入模板文件 <s ...

  3. jquery设置input不可编辑,背景变灰,鼠标变禁止

    先看效果 $("#id").attr("onfocus", "this.blur()"); $("#id").css(& ...

  4. [bzoj3060][Poi2012]Tour de Byteotia_并查集

    [Poi2012]Tour de Byteotia 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3060 题解: 这类题有一个套路,就是 ...

  5. [转帖]Intel 上一代 可扩展CPU的简单报价

    8.1万元人间毒物!Intel 28核铂金版Xeon 8180零售上市 http://news.mydrivers.com/1/541/541670.htm 猜你想看:英特尔 CPU处理器 Xeon ...

  6. rownum伪行号-排行榜-分页

    rownum伪行号-排行榜-分页 1.rownum 是oracle数据库特有的一个特性,它针对每一个查询(包括子查询),都会生成一个rownum用于对该次查询进行编号 2.每个rownum只针对当前s ...

  7. 【51nod】2591 最终讨伐

    [51nod]2591 最终讨伐 敲51nod是啥评测机啊,好几次都编译超时然后同一份代码莫名奇妙在众多0ms中忽然超时 这道题很简单就是\(M\)名既被诅咒也有石头的人,要么就把石头给没有石头被诅咒 ...

  8. codeforces 1249D1/D2 Too Many Segments (贪心)

    (点击此处查看原题) 题意说明 有n个区间,第i个区间覆盖范围[li,ri]内所有点,问删除最少哪些区间,使得所有点被区间覆盖的次数少于等于k次 解题思路 看到这个题的时候,觉得和开关(反转)问题很像 ...

  9. N分成不同的数相乘使答案最大

    题意:http://acm.hdu.edu.cn/showproblem.php?pid=5976 首先队友想出了分的越多答案越多. 我们就:2,3,4,5,6...多出来的尽量往小了加就行了. #d ...

  10. Python多线程VS多进程