三种方式构建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 ...
随机推荐
- Flutter中通过循环渲染组件
class ContactsState extends State<Contacts>{ List formList; initState() { super.initState(); f ...
- 如何设置payjs的微信jsapi支付目录
首先你得是 payjs 的有效开通用户.不清楚 payjs 是干什么的可以自行百度. 设置方法非常简单,在后台菜单-系统设置-JSAPI目录设置,在右侧填写支付目录即可. 需要注意的是:支付目录需要配 ...
- Guava源码阅读-base-Enums
package com.google.common.base; guava源码中对这个类的方法介绍只有一句话: Utility methods for working with {@link Enum ...
- 使用pycharm开发web——django2.1.5(四)视图和模板相关
刘老师说这块很重要..... 应该是很重要,大概看了一下,这里面关于views中函数作用,大概看来可能就是相应请求,传入数据和跳转,基本功能上貌似这些框架都差不多吧(其实我并没用过3个框架以上.... ...
- HttpServletResponse对象(转)
Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象.和代表响应的response对象.request和response对象即然代表请求和响应,那我们要 ...
- ObjectMapper 对象和json相互转换
一.ObjectMapper ObjectMapper类是Jackson库的主要类.它提供一些功能将转换成Java对象匹配JSON结构,反之亦然.它使用JsonParser和JsonGenerator ...
- ubuntu 18.04 LTS 安装ROS系统
不同的ubuntu系统对应着不同的ROS版本,如果装错了就会提示 E:无法定位软件包 ROS有Melodic.Lunar.Kinetic不同的种类对应着不同的ubuntu版本 Melodic主要对应: ...
- 剑指offer12:求解double类型的浮点数base和int类型的整数exponent的次方。 保证base和exponent不同时为0
1. 题目描述 给定一个double类型的浮点数base和int类型的整数exponent.求base的exponent次方.保证base和exponent不同时为0. 2. 思路和方法 分析: 由于 ...
- B - How many integers can you find
Now you get a number N, and a M-integers set, you should find out how many integers which are smal ...
- linux的定时器(timer_create,timer_gettime,timer_delete,SIGEV_SIGNAL)
ref : http://blog.chinaunix.net/uid-28458801-id-5035347.html 系统中的一个模块需要频繁的获取系统时间,使用linux中内置的函数开销过大 ...