Net中的并发锁
object _lock
锁的概念,这里不做详细阐述。先从最经典的应用场景来说,单例模式在不考虑静态构造函数实现的方式下,用锁实现是必须的。比如:
public class Singleton
{
private static Singleton _Singleton = null;
private static object Singleton_Lock = new object();
public static Singleton CreateInstance()
{
if (_Singleton == null)
{
lock (Singleton_Lock)
{
if (_Singleton == null)
{
_Singleton = new Singleton();
}
}
}
return _Singleton;
}
}
这里我们注意到
static object Singleton_Lock = new object()
这里的lock,其实是一个语法糖,具体定义就不多说,也不是本文的重点。简单说一下lock的注意事项
1. lock的对象必须是引用类型(string类型比较特殊,会被CLR‘暂留’,所以也不行)
2. lock推荐使用静态、私有、只读的对象。
3. 对于2中的只读,是需要保证在lock外无法修改。也补充了第一点中string类型不行的原因。
4. lock(this),如果无法保证外部及其他线程是否会访问,最好不要这样。因为可能会发生死锁。
综上,lock(readonly static referenceTypes)是最优雅的使用方式。
Net3.5中的ReaderWriterLockSlim
ReaderWriterLockSlim支持三种锁定模式
1. Read
2. Write
3. UpgradeableRead
这三种锁定模式所对应的方法分别是:
1. EnterReadLock
2. EnterWriteLock
3. EnterUpgradeableReadLock
其中,Read模式是共享锁定模式,任意线程都可以在此模式下同时获得锁。
Write模式是互斥模式,任意数量线程只允许一个线程进入该锁。
其实这篇博文的目的,就是为了测试传统Object_lock 和ReaderWriteLockSlim的性能差异。废话不多,实现上使用了赵姐夫的CodeTimer
测试代码如下:
public class MemoryCache<TKey, TValue>
{
private ConcurrentDictionary<TKey, TValue> _dicCache = new ConcurrentDictionary<TKey, TValue>();
private Dictionary<TKey, Lazy<TValue>> _dicLazyValue = new Dictionary<TKey, Lazy<TValue>>();
private ReaderWriterLockSlim _cacheLock = new ReaderWriterLockSlim();
private object _locker = new object();
public TValue GetValueByObjectLocker(TKey key, Lazy<TValue> value)
{
if (!_dicLazyValue.ContainsKey(key))
{
lock (_locker)
{
if (!_dicLazyValue.ContainsKey(key))
{
_dicLazyValue.Add(key, value);
}
}
}
if (_dicCache == null)
{
lock (_locker)
{
if (_dicCache == null)
{
_dicCache = new ConcurrentDictionary<TKey, TValue>();
}
}
}
return _dicCache.GetOrAdd(key, _dicLazyValue[key].Value);
}
public TValue GetValueByLockSlim(TKey key, Lazy<TValue> value)
{
if (!_dicLazyValue.ContainsKey(key))
{
try
{
_cacheLock.EnterWriteLock();
if (!_dicLazyValue.ContainsKey(key))
{
_dicLazyValue.Add(key, value);
}
}
finally
{
_cacheLock.ExitWriteLock();
}
}
if (_dicCache == null)
{
try
{
_cacheLock.EnterUpgradeableReadLock();
if (_dicCache == null)
{
_dicCache = new ConcurrentDictionary<TKey, TValue>();
}
}
finally
{
_cacheLock.ExitUpgradeableReadLock();
}
}
return _dicCache.GetOrAdd(key, _dicLazyValue[key].Value);
}
}
使用控制台应用程序
static void Main(string[] args)
{
MemoryCache<string, string> _memoryCache = new MemoryCache<string, string>();
CodeTimer.Initialize();
CodeTimer.Time("object lock", 1000, () =>
{
var lazyStr = new Lazy<string>(() => Thread.CurrentThread.ManagedThreadId.ToString());
_memoryCache.GetValueByObjectLocker("123", lazyStr);
});
CodeTimer.Time("LockSlim", 1000, () =>
{
var lazyStr = new Lazy<string>(() => Thread.CurrentThread.ManagedThreadId.ToString());
_memoryCache.GetValueByLockSlim("456", lazyStr);
});
System.Console.WriteLine("123");
System.Console.ReadLine();
}
结果:
object lock
Time Elapsed: 7ms
CPU Cycles: 6,414,332
Gen 0: 0
Gen 1: 0
Gen 2: 0
LockSlim
Time Elapsed: 1ms
CPU Cycles: 3,182,178
Gen 0: 0
Gen 1: 0
Gen 2: 0
综上,当下次有使用'锁'的时候,请优先考虑ReaderWriterLockSlim以获取更高的性能和更低的CPU Cycles.
Net中的并发锁的更多相关文章
- Redis学习笔记~Redis并发锁机制
回到目录 redis客户端驱动有很多,如ServiceStack.Redis,StackExchange.Redis等等,下面我使用ServiceStack.Redis为例,介绍一下在redis驱动中 ...
- 如何理解Java中眼花缭乱的各种并发锁?
在互联网公司面试中,很多小伙伴都被问到过关于锁的问题. 今天,我给大家一次性把Java并发锁的全家桶彻底讲明白.包括互斥锁.读写锁.重入锁.公平锁.悲观锁.自旋锁.偏向锁等等等等.视频有点长,大家一定 ...
- Java并发指南8:AQS中的公平锁与非公平锁,Condtion
一行一行源码分析清楚 AbstractQueuedSynchronizer (二) 转自https://www.javadoop.com/post/AbstractQueuedSynchronizer ...
- Redis修改数据多线程并发—Redis并发锁
本文版权归博客园和作者本人吴双共同所有 .转载爬虫请注明地址,博客园蜗牛 http://www.cnblogs.com/tdws/p/5712835.html 蜗牛Redis系列文章目录http:// ...
- WCF初探-28:WCF中的并发
理解WCF中的并发机制 在对WCF并发机制进行理解时,必须对WCF初探-27:WCF中的实例化进行理解,因为WCF中的并发特点是伴随着服务实例上下文实现的.WCF的实例上下文模型可以通过Instanc ...
- linux设备驱动第五篇:驱动中的并发与竟态
综述 在上一篇介绍了linux驱动的调试方法,这一篇介绍一下在驱动编程中会遇到的并发和竟态以及如何处理并发和竞争. 首先什么是并发与竟态呢?并发(concurrency)指的是多个执行单元同时.并行被 ...
- Python中的并发编程
简介 我们将一个正在运行的程序称为进程.每个进程都有它自己的系统状态,包含内存状态.打开文件列表.追踪指令执行情况的程序指针以及一个保存局部变量的调用栈.通常情况下,一个进程依照一个单序列控制流顺序执 ...
- 在 Java 中高效使用锁的技巧--转载
竞争锁是造成多线程应用程序性能瓶颈的主要原因 区分竞争锁和非竞争锁对性能的影响非常重要.如果一个锁自始至终只被一个线程使用,那么 JVM 有能力优化它带来的绝大部分损耗.如果一个锁被多个线程使用过,但 ...
- java高并发锁的3种实现
初级技巧 - 乐观锁 乐观锁适合这样的场景:读不会冲突,写会冲突.同时读的频率远大于写. 以下面的代码为例,悲观锁的实现: Java代码 public Object get(Object key) ...
随机推荐
- English:Day-to-day 1104
\ ------------------------------ editor by enomothem ------------------------------ It snowed throug ...
- JAVA工程师技能要求
近期做了个JAVA工程师分类, JAVA工程师可能是市场上最多类的程序员: 初级JAVA工程师的基本要求 Good basic programming skills 良好基本编程技能 Founda ...
- WCF、WebAPI、WCFREST、WebService的区别
目录导航: 1. WCF 2. WebAPI 3. WebService 4. WCFREST 5. 如何选择WCF.WebAPI.WCFREST.WebService 1.WCF 这个是基于SOAP ...
- tensorflow 神经网络模型概览;熟悉Eager 模式;
典型神经网络模型:(图片来源:https://github.com/madalinabuzau/tensorflow-eager-tutorials) 保持更新,更多内容请关注 cnblogs.com ...
- Cocos2d-x的坐标系统
推荐转至此处阅读<Cocos2d-x的坐标系统> Cocos2d-x的坐标系统 一.坐标系 二.Cocos2d-x的坐标系统 1.类别 2.定义 三.屏幕坐标系 & OpenGL坐 ...
- 使用原生代码实现一个Events模块,可以实现自定义事件的订阅、触发、移除功能
function Events() { // 放置所有添加的 监听事件 this._events = {} } Events.prototype = { on: function (name, fn, ...
- Java面试题和解答(五)
1.在Java中Executor和Executors的区别? Executor是线程池的顶层接口,它的实现类如下图所示: Executors是一个类,提供了多个静态方法,用于生成不同类型的线程池,如下 ...
- 带有Spring Boot和MySQL的Docker:简介(Part 1)
通过优锐课java学习分享中,我们看一下带有Spring Boot和MySQL的Docker教程.非常实用,分享给大家参考学习. Docker是一种技术,开发人员或DevOps团队可以使用容器来构建, ...
- PHP strstr 字符串函数
定义和用法 strstr - 查找字符串的首次出现 版本支持 PHP4 PHP5 PHP7 支持 支持 支持 V5.3.0 新增可选的 before_needle 参数. V4.3.0 strstr( ...
- JavaScript动态加载script方式引用百度地图API 拓展---JavaScript的Promise
上一篇博客JavaScript动态加载script方式引用百度地图API,Uncaught ReferenceError: BMap is not defined 这篇文章中我接触到一个新的单词:Pr ...