面试官: 平时开发中你用过读写锁吗?

前面实现了一个 带值变更通知能力的字典类(线程不安全),童鞋们有没有发现演示代码使用了 lock语法糖, 这个有没有问题呢?

没背景说个铲铲

      同程艺龙基础架构部推出的数据获取组件DAL.Connection,我们要做到在切换连接配置时清空数据库连接池, 这就涉及到切换连接的时候,触发变更通知。

•.NET 如何清空连接池?•面试官:实现一个带值变更通知能力的Dictionary

仔细阅读《面试官:实现一个带值变更通知能力的Dictionary》一文的童靴们有没有发现一个细节:我使用了lock语法糖无脑加锁。

这里面有个前置知识点:C# Dictionary线程不安全。
什么叫线程不安全,请看这个✍️ 你管这叫"线程安全"?

       这在高并发下会有问题:大多数时候下DBA并不会变更业务方的数据库连接,这是一个多读少写的场景, 我们无脑使用lock在多数时间会人为阻塞请求。

到这个时候,我们就要想到读写锁ReaderWriterLockSlim

宝藏好物:ReaderWriterLockSlim

Use ReaderWriterLockSlim to protect a resource that is read by multiple threads and written to by one thread at a time. ReaderWriterLockSlim allows multiple threads to be in read mode, allows one thread to be in write mode with exclusive ownership of the lock, and allows one thread that has read access to be in upgradeable read mode, from which the thread can upgrade to write mode without having to relinquish its read access to the resource.

简而言之:

ReaderWriterLockSlim提供对某资源在某时刻下的多线程同读 或 单线程独占写。
此外,ReaderWriterLockSlim还提供从读模式无缝升级到独占写模式。

总结下来:

读写锁处于以下四种状态:

1.未进入: 没有线程进入锁(或者所有线程退出锁)2.读模式:每次调用EnterReadlock时,锁计数都会增加,但允许您读取其中的代码块。3.写模式:独占、排他4.可升级的读模式(upgradeable read mode):多线程读,其中一个线程具备在某时刻升级到排他写模式的可能。

btw,读写锁相比常规lock之外,还具备锁超时的机制,能避免未知原因持续占有锁导致的死锁。

这就很适合我们开发DAL.Connection组件的多读少写的场景。 

微软ReaderWriterLockSlim页面还很贴心的给了一个基于读写锁的缓存操作封装类SynchronizedCache

开箱即用的缓存操作类

基于ReaderWriterLockSlim对线程不安全的Dictionary进行了包装, 可以作为一个多读少写的缓存操作类。

public class SynchronizedCache 
{private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();private Dictionary<int, string> innerCache = new Dictionary<int, string>();public int Count{ get { return innerCache.Count; } }public string Read(int key){cacheLock.EnterReadLock();try{return innerCache[key];}finally{cacheLock.ExitReadLock();}}public void Add(int key, string value){cacheLock.EnterWriteLock();try{innerCache.Add(key, value);}finally{cacheLock.ExitWriteLock();}}public bool AddWithTimeout(int key, string value, int timeout){if (cacheLock.TryEnterWriteLock(timeout)){try{innerCache.Add(key, value);}finally{cacheLock.ExitWriteLock();}return true;}else{return false;}}public AddOrUpdateStatus AddOrUpdate(int key, string value){cacheLock.EnterUpgradeableReadLock();try{string result = null;if (innerCache.TryGetValue(key, out result)){if (result == value){return AddOrUpdateStatus.Unchanged;}else{cacheLock.EnterWriteLock();try{innerCache[key] = value;}finally{cacheLock.ExitWriteLock();}return AddOrUpdateStatus.Updated;}}else{cacheLock.EnterWriteLock();try{innerCache.Add(key, value);}finally{cacheLock.ExitWriteLock();}return AddOrUpdateStatus.Added;}}finally{cacheLock.ExitUpgradeableReadLock();}}public void Delete(int key){cacheLock.EnterWriteLock();try{innerCache.Remove(key);}finally{cacheLock.ExitWriteLock();}}public enum AddOrUpdateStatus{Added,Updated,Unchanged};~SynchronizedCache(){if (cacheLock != null) cacheLock.Dispose();}
}

缓存操作类SynchronizedCache每次操作会返回操作结果,和常见的字典一样,不带值变更通知的能力,我们还是像《面试官:实现一个带值变更通知能力的Dictionary》 一文那样,添加值变更事件,注册变更逻辑。

public event EventHandler<ValueChangedEventArgs<string>> OnValueChanged;//--- 节选自AddOrUpdate方法
cacheLock.EnterWriteLock();
try
{OnValueChanged?.Invoke(this, new ValueChangedEventArgs<string>(key));innerCache[key] = value;
}
finally
{cacheLock.ExitWriteLock();
}
return AddOrUpdateStatus.Updated;//---if (sc.AddOrUpdate(key, value) == SynchronizedCache.AddOrUpdateStatus.Updated)
{Console.WriteLine($"已经发生了值变更,原key对应的键值已经被重写。");}
}  

输出旁白

      本文记录了读写锁在日常开发中的实践,大多数场景都是多读少写,读者可以思考一下是不是也可以将项目中的无脑lock替换为SynchronizedCache

      本文是同程艺龙DAL.Connection组件研发过程的一个小插曲,有心的读者可以往上翻一翻,了解上下文背景、了解小码甲的思考过程。

这就像我们高中做数学题,直接看答案并不能快速提升,结合上下文自然、流畅的转到这个方向才是最重要的。

最后,觉得有用,一键三连,激浊扬清❤️。

目前100000+人已关注加入我们

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/298798.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何计算一只鸡的表面积?各大专业的奇葩解法

全世界只有3.14 % 的人关注了爆炸吧知识今天&#xff0c;知识君跟大家来算一下一只鸡的表面积吧。数学系

ArrayPool 源码解读之 byte[] 也能池化?

一&#xff1a;背景 1. 讲故事最近在分析一个 dump 的过程中发现其在 gen2 和 LOH 上有不少size较大的free&#xff0c;仔细看了下&#xff0c;这些free生前大多都是模板引擎生成的html片段的byte[]数组&#xff0c;当然这篇我不是来分析dump的&#xff0c;而是来聊一下&#x…

为什么有些人从不点开朋友圈?

全世界只有3.14 % 的人关注了爆炸吧知识真正决定人与人之间的差距的&#xff0c;其实是我们对事物的见识与内心的格局&#xff0c;见识的深浅决定人生的深浅&#xff0c;格局的大小决定了人生之路是宽是窄。今天给大家推荐几个有深度、有想法的公众号&#xff0c;希望能够给你带…

wxPython:登录工具

最近一直在学习Python的基础和一些常用的模块&#xff0c;现在该是付诸实践的时候了。 我打算做的第一个小工具是利用wxPython来创建一个登录小工具&#xff0c;这主要是减轻自己日常工作中的一些负担。具体需求是这样的&#xff0c;在出现工具的UI之后&#xff0c;用户可以选择…

微信 小程序 python 渲染_微信小程序渲染html内容

最近又做了一个新的小程序关于物流订单查询欢迎来体验遇到了一个小问题&#xff1a;数据中返回电话号码的字符串识别出来并且高亮和可以绑定事件。比如数据中包含您的派送员黄xx正在派件&#xff0c;电话&#xff1a;137xxxx41460已经在派送。其中就要识别出137xxxx41460并且绑…

shell oracle查询数组,shell 脚本 ---数组

数组的定义&#xff1a;所谓数组&#xff0c;就是相同数据类型的元素按一定顺序的集合&#xff0c;就是把有限个类型相同的变量用一个名字命令&#xff0c;也就是说这些变量被定义成数组之后&#xff0c;它们就不在有自己的名字了&#xff0c;那么我们怎么找到各个变量或者元素…

Dockerfile 使用 ARG 参数实现构建模板

Dockerfile 使用 ARG 参数实现构建模板IntroDockerfile 里用来表示变量的主要有两个东西&#xff0c;一个是 ENV 代表了环境变量&#xff0c;另外一个则是 ARG 代表是构建 docker 镜像时的一个构建参数&#xff0c;需要在执行 docker build 命令时指定变量的值&#xff0c;最近…

华人AI界痛失“一代宗师”,计算机视觉之父黄煦涛教授去世

全世界只有3.14 % 的人关注了爆炸吧知识美东时间2020年4月25日夜间&#xff0c;华人计算机视觉一代宗师&#xff0c;黄煦涛教授&#xff08;Thomas S. Huang&#xff09;在美国印第安纳州逝世&#xff0c;享年 84 岁。由于他在图像处理、模式识别等计算机视觉领域作出的开创性贡…

oracle 参照完整性,Oracle中用表外键来保证系统参照完整性

欢迎进入Oracle社区论坛&#xff0c;与200万技术人员互动交流 >>进入 Oracle中表的外键是保证系统参照完整性的手段&#xff0c;而参照完整性是指分布在两个表中的列所满足的具有主从性质的约束关系。外键涉及到两个表&#xff0c;其中一个称之为父项表&#xff0c;另一个…

你好,同学!在云端学习最潮的技术吧!

开学季大礼包9月开学了&#xff0c;作为学生的你&#xff0c;有想过在这个数字化年代&#xff0c;学最cool的技术吗&#xff1f;人工智能&#xff0c;物联网&#xff0c;云计算&#xff0c;还有区块链这些互联网产物影响着你的生活&#xff0c;也影响着你将来的职业发展。不论你…

seo关键词互点软件报价_SEO关键词优化收费问题和外包报价问题,一文详解

在竞争日益激烈的市场环境中&#xff0c;企业为了在互联网平台中获得较好的排名&#xff0c;以及实现产品的较好变现&#xff0c;大多数都是使用SEO搜索引擎&#xff0c;因为通过优化关键词可以不断地为用户创造“用户最想得到的”“最匹配”搜索结果&#xff0c;在快速找到心仪…

15张令人震撼的物理动图,看完惊呆了!

全世界只有3.14 % 的人关注了爆炸吧知识比抖音还上瘾看了会让人上瘾的物理动图&#xff0c;赶紧给家里的孩子看看吧&#xff0c;绝对让他开拓眼界&#xff0c;脑洞大开。1.有弹性的岩浆2.高速转动时&#xff0c;因向心力不足而被撕开的的CD&#xff08;慢镜头&#xff09;3.震荡…

linux目录结果说明,Linux目录结构及文件说明

Linux中所有文件都是从(/)根开始的&#xff0c;下面是典型的Linux目录结构说明&#xff1a;/&#xff1a;根目录/bin&#xff1a; binary 主要用来存放可执行文件/sbin&#xff1a; super bin 存放系统管理程序&#xff0c;通常只有管理员才有权限使用/boot&#xff1a; 存放内…

Java wait notify

2019独角兽企业重金招聘Python工程师标准>>> Java wait && notify ‍wait、notify和notifyAll方法是Object类的final native方法&#xff0c;所以这些方法不能被子类重写。 方法 notifyAll() Wakes up all threads that are waiting on this objects monito…

使用ETag协议实现ASP.NET Core API缓存

通常&#xff0c;我们在ASP.NET Core API服务端实现缓存&#xff0c;数据直接从缓存中取出&#xff0c;返回给客户端&#xff0c;以便加快响应速度。但是这样的做法&#xff0c;解决不了数据传输到客户端需要占用带宽带来的性能问题。这时&#xff0c;可以尝试使用ETag。ETag协…

深度优化sql 查询, 提升性能一百倍是什么概念?

正在做一个软件设计, 希望有个功能, 然而, 对于加上该功能后对系统性能造成的影响很是担忧. 可以说是, 一方面想要有这个功能, 另一方面又对性能问题是否能够解决很怀疑, 正处于犹豫不决状态. 于是决定进行实验. 首先对表结构和索引进行了优化, 初步结果还不错, 性能基本进入可…

女老师vs男老师的区别...

1 被帅到了2 失传已久的如来神掌&#xff1f;&#xff1f;&#xff01;&#xff01;3 哎呦&#xff0c;谁拉我一把&#xff1f;4 决定到底要不要开始学习的我…5 女老师vs男老师监考的区别...6 函数广播体操7 这个打包装置够便捷&#xff0c;够酷炫&#xff01;关键是省事你点的…

Redis Windows环境安装

1、下载Windows 版本 Redis: https://github.com/ServiceStack/redis-windows 2、 解压文件&#xff1a; F:\开源代码学习\01_Redis 打开 目录&#xff1a;F:\开源代码学习\01_Redis\src\msopentech\redis64-2.6.12.1 3、启动Redis 指向CMD命令&#xff1a; 4、测试安装成果&am…

Hello Blazor:(11)全局截获事件执行

前言在Blazor中&#xff0c;我们使用on{DOM EVENT}"{DELEGATE}"这样的Razor语法在组件标记中指定委托事件处理程序&#xff1a;<button onclick"IncrementCount">Click me</button>但是没有提供解除委托的方法。比如&#xff0c;我们需要在某种…