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

前面实现了一个 带值变更通知能力的字典类(线程不安全),童鞋们有没有发现演示代码使用了 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;知识君跟大家来算一下一只鸡的表面积吧。数学系

文件夹里打开终端

$sudo apt-get install nautilus-open-terminal 这样便会在每个文件夹的右键菜单中出现 "在终端中打开" 的一个选项, 选择便会打开一个终端, 路径为当前文件夹! 当然, 可以使用 nautilus-scripts 添加右键扩展. 在 ~/.gnome2/nautilus-scripts/ 目录下新建一个文件名…

如何删除SQL Server下注册的服务器

删除对应的sql server的注册服务器&#xff1a; HKEY_CURRENT_USER\Software\Microsoft\Microsoft SQL Server\80\Tools\SQLEW\Registered Servers X\SQL Server 组中&#xff0c; 直接删除你你要删除的那个注册名就可以了 转载于:https://www.cnblogs.com/tohen/archive/2010/…

oracle绑定变量过多,oracle - 在SQL Plus中使用绑定变量并返回多行? - 堆栈内存溢出...

这是一个愚蠢的问题&#xff0c;但我似乎无法解决。 我有一个查询在OCI程序中引起麻烦&#xff0c;因此我想在SQL * Plus中手动运行它以检查是否有任何区别。 这是查询&#xff1a;select e.label as doc_name,e.url,i.item_id,multi as form_typefrom cr_items i, cr_extlinks…

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

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

本地环境和测试环境搭建

1.wampserver&#xff08;可兼容后端php&#xff09; 2.tomcate 3.edp webserver&#xff08;百度内部&#xff09; 4.fiddle重定向&#xff08;可以把在线的网页直接接入本地的代码进行替换看效果&#xff09;转载于:https://www.cnblogs.com/cjy1993/p/4097123.html

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

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

wxPython:登录工具

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

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

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

淘宝一淘网收录部分垂直B2C网站信息

12月23日下午消息&#xff0c;淘宝旗下一淘网搜索近日悄然收录当当、红孩子等垂直B2C网站的折扣信息&#xff0c;网友可轻松在外部垂直B2C网站和淘宝站内商家间做出对比和选择。 之前有消息称&#xff0c;淘宝网已经通过站内搜索中的“导购”功能已经实现了与一淘的互通&#…

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

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

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

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

关于更换液晶屏(LCD)后“输入不支援”的一种解决方案

今天新装了一台监控主机&#xff0c;一切调试完毕之后就装箱了。没想到拿到客户那里之后却出现了一个小小的问题&#xff0c;XP进度条跳过之后显示器出现“输入不支援”&#xff0c;反复重启之后仍然无法解决&#xff0c;自己在公司刚刚调试好了的呀&#xff0c;哦想起来了&…

python 数据驱动接口自动化框架_python接口自动化测试 - 数据驱动DDT模块的简单使用...

DDT简单介绍 名称&#xff1a;Data-Driven Tests&#xff0c;数据驱动测试 作用&#xff1a;由外部数据集合来驱动测试用例的执行 核心的思想&#xff1a;数据和测试代码分离 应用场景&#xff1a;一组外部数据来执行相同的操作 优点&#xff1a;当测试数据发生大量变化的情况下…

【知识分享】异步调用与多线程的区别

随着拥有多个硬线程CPU&#xff08;超线程、双核&#xff09;的普及&#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;另一个…

关于数据仓库 — 总体工具介绍

数据仓库项目是以关系数据库为依托&#xff0c;以数据仓库理论为指导、以 OLAP为多层次多视角分析&#xff0c;以 ETL工具进行数据集成、整合、清洗、加载转换&#xff0c;以前端工具进行前端报表展现浏览&#xff0c;以反复叠代验证为生命周期的综合处理过程。最终目标是为了达…