文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2024-12-14 00:59

关注

本文转载自微信公众号「精益码农」,作者小码甲。转载本文请联系精益码农公众号。

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

没背景说个铲铲

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

这在高并发下会有问题:大多数时候下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还提供从读模式无缝升级到独占写模式。

总结下来:

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

未进入: 没有线程进入锁(或者所有线程退出锁)

读模式:每次调用EnterReadlock时,锁计数都会增加,但允许您读取其中的代码块。

写模式:独占、排他

可升级的读模式(upgradeable read mode):多线程读,其中一个线程具备在某时刻升级到排他写模式的可能。

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

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

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

开箱即用的缓存操作类

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

  1. public class SynchronizedCache  
  2.     private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim(); 
  3.     private Dictionary<int, string> innerCache = new Dictionary<int, string>(); 
  4.  
  5.     public int Count 
  6.     { get { return innerCache.Count; } } 
  7.  
  8.     public string Read(int key
  9.     { 
  10.         cacheLock.EnterReadLock(); 
  11.         try 
  12.         { 
  13.             return innerCache[key]; 
  14.         } 
  15.         finally 
  16.         { 
  17.             cacheLock.ExitReadLock(); 
  18.         } 
  19.     } 
  20.  
  21.     public void Add(int key, string value) 
  22.     { 
  23.         cacheLock.EnterWriteLock(); 
  24.         try 
  25.         { 
  26.             innerCache.Add(key, value); 
  27.         } 
  28.         finally 
  29.         { 
  30.             cacheLock.ExitWriteLock(); 
  31.         } 
  32.     } 
  33.  
  34.     public bool AddWithTimeout(int key, string value, int timeout) 
  35.     { 
  36.         if (cacheLock.TryEnterWriteLock(timeout)) 
  37.         { 
  38.             try 
  39.             { 
  40.                 innerCache.Add(key, value); 
  41.             } 
  42.             finally 
  43.             { 
  44.                 cacheLock.ExitWriteLock(); 
  45.             } 
  46.             return true
  47.         } 
  48.         else 
  49.         { 
  50.             return false
  51.         } 
  52.     } 
  53.  
  54.     public AddOrUpdateStatus AddOrUpdate(int key, string value) 
  55.     { 
  56.         cacheLock.EnterUpgradeableReadLock(); 
  57.         try 
  58.         { 
  59.             string result = null
  60.             if (innerCache.TryGetValue(keyout result)) 
  61.             { 
  62.                 if (result == value) 
  63.                 { 
  64.                     return AddOrUpdateStatus.Unchanged; 
  65.                 } 
  66.                 else 
  67.                 { 
  68.                     cacheLock.EnterWriteLock(); 
  69.                     try 
  70.                     { 
  71.                         innerCache[key] = value; 
  72.                     } 
  73.                     finally 
  74.                     { 
  75.                         cacheLock.ExitWriteLock(); 
  76.                     } 
  77.                     return AddOrUpdateStatus.Updated; 
  78.                 } 
  79.             } 
  80.             else 
  81.             { 
  82.                 cacheLock.EnterWriteLock(); 
  83.                 try 
  84.                 { 
  85.                     innerCache.Add(key, value); 
  86.                 } 
  87.                 finally 
  88.                 { 
  89.                     cacheLock.ExitWriteLock(); 
  90.                 } 
  91.                 return AddOrUpdateStatus.Added; 
  92.             } 
  93.         } 
  94.         finally 
  95.         { 
  96.             cacheLock.ExitUpgradeableReadLock(); 
  97.         } 
  98.     } 
  99.  
  100.     public void Delete(int key
  101.     { 
  102.         cacheLock.EnterWriteLock(); 
  103.         try 
  104.         { 
  105.             innerCache.Remove(key); 
  106.         } 
  107.         finally 
  108.         { 
  109.             cacheLock.ExitWriteLock(); 
  110.         } 
  111.     } 
  112.  
  113.     public enum AddOrUpdateStatus 
  114.     { 
  115.         Added, 
  116.         Updated, 
  117.         Unchanged 
  118.     }; 
  119.  
  120.     ~SynchronizedCache() 
  121.     { 
  122.        if (cacheLock != null) cacheLock.Dispose(); 
  123.     } 

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

  1. public event EventHandler> OnValueChanged; 
  2.  
  3. //--- 节选自AddOrUpdate方法 
  4. cacheLock.EnterWriteLock(); 
  5. try 
  6.    OnValueChanged?.Invoke(this, new ValueChangedEventArgs(key)); 
  7.    innerCache[key] = value; 
  8. finally 
  9.     cacheLock.ExitWriteLock(); 
  10. return AddOrUpdateStatus.Updated; 
  11.                          
  12. //--- 
  13.  
  14. if (sc.AddOrUpdate(key, value) == SynchronizedCache.AddOrUpdateStatus.Updated) 
  15.     Console.WriteLine($"已经发生了值变更,原key对应的键值已经被重写。");} 
  16. }   

输出旁白

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

 

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

 

来源:精益码农内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯