三种方式构建C#单例模式
/// <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#单例模式的更多相关文章
- 彻底了解构建 JSON 字符串的三种方式
原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7701856.html 前言:JSON 是轻量级的数据交换格式,很常用,尤其是在使用 Ajax ...
- python实现单例模式的三种方式及相关知识解释
python实现单例模式的三种方式及相关知识解释 模块模式 装饰器模式 父类重写new继承 单例模式作为最常用的设计模式,在面试中很可能遇到要求手写.从最近的学习python的经验而言,singlet ...
- Solon 开发,三、构建一个Bean的三种方式
Solon 开发 一.注入或手动获取配置 二.注入或手动获取Bean 三.构建一个Bean的三种方式 四.Bean 扫描的三种方式 五.切面与环绕拦截 六.提取Bean的函数进行定制开发 七.自定义注 ...
- C#批量插入数据到Sqlserver中的三种方式
本篇,我将来讲解一下在Sqlserver中批量插入数据. 先创建一个用来测试的数据库和表,为了让插入数据更快,表中主键采用的是GUID,表中没有创建任何索引.GUID必然是比自增长要快的,因为你生 成 ...
- PHP的学习--连接MySQL的三种方式
记录一下PHP连接MySQL的三种方式. 先mock一下数据,可以执行一下sql. /*创建数据库*/ CREATE DATABASE IF NOT EXISTS `test`; /*选择数据库*/ ...
- php 链接mysql的三种方式对比
PHP连接Mysql的三种方式: 1.原生的连接方式 原生的连接方式是面向过程的写法 <?php $host = 'localhost'; $database = 'test'; $usern ...
- dubbo服务运行的三种方式
dubbo服务运行,也就是让生产服务的进程一直启动.如果生产者进程挂掉,也就不存在生产者,消费者不能进行消费. Dubbo服务运行的三种方式如下:1.使用Servlet容器运行(Tomcat.Jett ...
- python 全栈开发,Day94(Promise,箭头函数,Django REST framework,生成json数据三种方式,serializers,Postman使用,外部python脚本调用django)
昨日内容回顾 1. 内容回顾 1. VueX VueX分三部分 1. state 2. mutations 3. actions 存放数据 修改数据的唯一方式 异步操作 修改state中数据的步骤: ...
- Spring MVC异常统一处理的三种方式
Spring 统一异常处理有 3 种方式,分别为: 使用 @ ExceptionHandler 注解 实现 HandlerExceptionResolver 接口 使用 @controlleradvi ...
随机推荐
- 针对thinkphp 5框架存储过程bug而重写的存储过程的扩展类
近期用tp5框架调取存储过程发现有bug,借鉴了一些官方的函数.以及找了个mysqli的类把存储过程重新写了个扩展类,下面两个类直接放置项目extend目录的stored(这个文件夹名称请按个人习惯命 ...
- 如何用最快的速度读出大小为10G的文件的行数?弄懂 python 的迭代器
with open('rm_keys.txt', 'r', encoding = 'utf-8') as f: count = 0 for line in f: 7 count += 1 print( ...
- Java基础——值传递
值传递? 参数传递的值的拷贝,改变拷贝不影响原参数. 引用传递? 参数传递的是参数本身,改变形参,实参也改变. Java中是什么传递? Java中只有值传递 实际情况为什么不对呢? 1. 基本数据类型 ...
- Mac PyCharm2019激活方法
此教程支持最新2019.2版本Pycharm及其他软件 此教程实时更新,请放心使用:如果有新版本出现猪哥都会第一时间尝试激活: pycharm官网下载地址:http://www.jetbrains.c ...
- 利用NPOI导出Word文档帮助类
/// <summary> /// NPOI操作Word /// </summary> public class NpoiWordHelper { /// <summar ...
- PTA(Advanced Level)1044.Shopping in Mars
Shopping in Mars is quite a different experience. The Mars people pay by chained diamonds. Each diam ...
- [转帖]Cookie与Passport安全
Cookie与Passport安全 https://www.cnblogs.com/xinzhao/p/6395153.html 感觉自己对网络安全性的理解还是不深入 不透彻. 对于web系统而言,由 ...
- java网络编程-面试题
1.网络编程时的同步.异步.阻塞.非阻塞? 同步:函数调用在没得到结果之前,没有调用结果,不返回任何结果.异步:函数调用在没得到结果之前,没有调用结果,返回状态信息.阻塞:函数调用在没得到结果之前,当 ...
- (二十二)自定义简化版JDBC(Dbutils框架的设计思想)
目录 元数据概念 DataBaseMetaData ParameterMetaData ResultSetMetaData 编写简化版的JDBC O-R Mapping 概念 自定义简化版JDBC 元 ...
- Go-常识补充-切片-map(类似字典)-字符串-指针-结构体
目录 Go 常识补充 Go 命名 打印变量类型科普 _ 关键字 命名规范相关 包目录规范 切片 多维切片 切片初始化的方法 多维切片初始化 切片删除元素(会略微影响效率 ,少用) copy 函数 打散 ...