线程安全单例最佳实践,C#中的Lazy是如何保证线程安全的
在.NET 4.0之后,.NET Framework中提供了一种安全的延迟加载类型Lazy
Lazy能够在多线程环境下,保证GetValue函数只执行一次,从而实现单例模式
在过去,实现单例模式我们通常使用二次判断锁,或者利用类的静态初始化函数
利用Lazy类型,能够简化这一过程,并且性能上更好
Lazy创建的时候可以指定线程安装模式,目前有两种模式,PublicationOnly,ExcutionAndPublication
PublicationOnly模式
boxed = CreateValue(); //
if (boxed == null ||
Interlocked.CompareExchange(ref m_boxed, boxed, null) != null) //
{
boxed = (Boxed)m_boxed; //
}
else
{
m_valueFactory = ALREADY_INVOKED_SENTINEL; //
}
1.运行初始化函数,装箱到一个内部Box类型中,解决null值判断的问题,如果已经创建的情况,会返回null,该过程是线程不安全的
2.判断m_boxed是否为空,m_boxed是value保存的字段,如果等于空则设置为boxed,该方法能保证原子性,该过程是线程安全的
3.如果CreateValue返回空,表示其他线程已经创建有实例,则设置为已经创建好的实例
4.将初始化方法标记为已经初始化,一般发生在并发运行情况下,多次运行CreateValue
PublicationOnly模式下使用基于Interlocked.CompareExchange实现的乐观锁,该类包含了原子性方法 CAS(Compare and swap)
CAS是利用CPU提供的原子性指令来实现,不同运行时版本可能有不一样实现
Interlocked具体的实现在Native方法中,有兴趣的朋友可以通过coreclr/jvm代码查看具体实现
这种模式下,单例函数可能多次运行,但是最终能保证获取到的实例只有一个
ExcutionAndPublication模式下使用的是Volatile+Monitor,Monitor就是lock语句的实现,Monitor实现在Native代码中,是重量级的锁
Monitor支持队列和线程睡眠,能够保证一整个方法块处于单线程执行状态
object threadSafeObj = Volatile.Read(ref m_threadSafeObj); //强制从主内存空间同步变量到线程内存空间副本
bool lockTaken = false;
try
{
if (threadSafeObj != (object)ALREADY_INVOKED_SENTINEL) //此时会有多个线程获取到正确值,抢夺开始
Monitor.Enter(threadSafeObj, ref lockTaken); //尝试等待锁,进入成功设置lockTaken为true
else
Contract.Assert(m_boxed != null);
//单线程代码块 Start
if (m_boxed == null) //没有设置值的情况
{
boxed = CreateValue(); //获取值
m_boxed = boxed; //设置到字段中
Volatile.Write(ref m_threadSafeObj, ALREADY_INVOKED_SENTINEL); //强制将线程内存空间副本写入到主内存空间
}
else // got the lock but the value is not null anymore, check if it is created by another thread or faulted and throw if so
{
boxed = m_boxed as Boxed;
if (boxed == null) // it is not Boxed, so it is a LazyInternalExceptionHolder
{
LazyInternalExceptionHolder exHolder = m_boxed as LazyInternalExceptionHolder;
Contract.Assert(exHolder != null);
exHolder.m_edi.Throw();
}
}
//单线程代码块End
}
finally
{
if (lockTaken) //进入成功需要释放,避免死锁
Monitor.Exit(threadSafeObj);
}
线程安全单例最佳实践,C#中的Lazy是如何保证线程安全的的更多相关文章
- java双重检测或枚举类实现线程安全单例(懒汉模式)
双重检测实现 /** * 懒汉模式->双重同步锁单例模式 */ public class SingletonExample5 { private SingletonExample5() { } ...
- muduo网络库源码学习————线程本地单例类封装
muduo库中线程本地单例类封装代码是ThreadLocalSingleton.h 如下所示: //线程本地单例类封装 // Use of this source code is governed b ...
- Swift百万线程攻破单例(Singleton)模式
一.不安全的单例实现 在上一篇文章我们给出了单例的设计模式,直接给出了线程安全的实现方法.单例的实现有多种方法,如下面: class SwiftSingleton { class var shared ...
- Java-多线程与单例
最近在公司写需求时遇到了多线程与单例一同出现的情况. 这个时候想到的就是线程安全以及单例的定义了,虽然单例指的是在内存中它只有一份,但是并不是说就是线程安全的. 所以,我当时就到网上找了关于多线程下单 ...
- 不使用synchronized和lock 锁实现线程安全单例
单例实现方式一,锁机制 public class Singleton { private static Singleton singleton=null; public Singleton() { } ...
- 【设计模式】单例设计模式的N中Java实现方法
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17359719 特点 单例模式的特点: 1.只能有一个实例: 2.必须自己创建自己的一个实例 ...
- java线程安全单例
public class MySingleton { // 使用volatile关键字保其可见性 volatile private static MySingleton instance = null ...
- Spring中构造器、init-method、@PostConstruct、afterPropertiesSet孰先孰后,自动注入发生时间以及单例多例的区别、SSH线程安全问题
首先明白,spring的IOC功能需要是利用反射原理,反射获取类的无参构造方法创建对象,如果一个类没有无参的构造方法spring是不会创建对象的.在这里需要提醒一下,如果我们在class中没有显示的声 ...
- 无锁,线程安全,延迟加载的单例实现(C#)
单例(singleton)是非常常见,也非常有用的设计模式,当然了, 面试中也是经常会被问到的:)在几乎所有的项目中都能看到它的身影.简而言之,单例保证了一个自定义类型在整个程序的生命周期只被创建一次 ...
随机推荐
- 2018.08.09洛谷P3959 宝藏(随机化贪心)
传送门 回想起了自己赛场上乱搜的20分. 好吧现在也就是写了一个随机化贪心就水过去了,不得不说随机化贪心大法好. 代码: #include<bits/stdc++.h> using nam ...
- cmake-add_definitions
add_definitions: Adds -D define flags to the compilation of source files. add_definitions(-DFOO -DBA ...
- python 按行读取判断是否为空
for line in fr.readlines(): try: # print(len(line)) if(len(line)==1): continue else: fw.write(matche ...
- 20155226 2016-2017-2 《Java程序设计》第7周学习总结
20155226 2016-2017-2 <Java程序设计>第7周学习总结 教材学习内容总结 认识时间与日期 六个时间基准: 1.格林威治标准时间 2.世界时 3.国际原子时 4.世界协 ...
- faceswap linux安裝教程
http://www.mamicode.com/info-detail-2602743.html https://blog.csdn.net/sinat_26918145/article/detail ...
- (最短路 spfa)Wormholes -- poj -- 3259
http://poj.org/problem?id=3259 Wormholes Time Limit: 2000MS Memory Limit: 65536K Total Submissions ...
- 使用WinSCP在Windows和Linux系统之间传输文件
小梅哥编写,未经许可,严禁用于任何商业用途 2018年6月30日 在日常SoC开发中,我们经常需要在Windows和Linux系统之间传输文件,例如在Windows系统上的DS-5集成开发环境中编写好 ...
- Linux C 创建目录函数mkdir相关【转】
转自:http://blog.csdn.net/fallenink/article/details/8480483 原文地址:http://sharp2wing.iteye.com/blog/1280 ...
- float 为什么不能用== ,或者大于等于,或者小于等于
本文尝试着将以下内容做一个浅显的解释,主要包括浮点数为什么是不精确的,浮点数为什么不能用==和!=直接比较,以及浮点数的比较方法等几个方面.如果那个地方说的不对还请各位看官不吝赐教!欢迎大家评论区讨论 ...
- Spring MVC深入讲解
一.前言: 大家好,Spring3 MVC是非常优秀的MVC框架,由其是在3.0版本发布后,现在有越来越多的团队选择了Spring3 MVC了.Spring3 MVC结构简单,应了那句话简单就是美,而 ...