最近由于项目上面建议使用读写锁,而去除常见的lock锁。然后就按照需求封装了下锁。以简化锁的使用。但是开发C#的童鞋都知道lock关键字用起太方便了,但是lock关键字不支持超时处理。很无奈,为了实现类似lock的功能。于是通过使用using关键字和IDisposable实现了自己的锁方法

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. ReadWriteUtilTest();
  6. MonitorUtilTest();
  7. Console.ReadLine();
  8. }
  9. private static void MonitorUtilTest()
  10. {
  11. MonitorUtil util = new MonitorUtil();
  12. int num = ;
  13. for (int index = ; index < ; index++)
  14. {
  15. var th = new Thread(new ThreadStart(() =>
  16. {
  17. Thread.Sleep();
  18. for (int i = ; i < ; i++)
  19. {
  20. using (util.GetLock("hello"))
  21. {
  22. num++;
  23. Console.WriteLine("num={0}", num);
  24. }
  25. }
  26. }));
  27.  
  28. th.Start();
  29. }
  30. }
  31.  
  32. private static void ReadWriteUtilTest()
  33. {
  34. ReadWriteLockUtil utl = new ReadWriteLockUtil();
  35. Int32 num = ;
  36. for (var i = ; i < ; i++)
  37. {
  38. Task.Factory.StartNew(() =>
  39. {
  40. while (true)
  41. {
  42. using (utl.GetLock("hello", ReadWriteLockUtil.ReadWriteEnum.Read))
  43. {
  44. Console.WriteLine("num={0}", num);
  45. Thread.Sleep();
  46. }
  47. }
  48. });
  49. }
  50. Task.Factory.StartNew(() =>
  51. {
  52. while (true)
  53. {
  54. using (utl.GetLock("hello", ReadWriteLockUtil.ReadWriteEnum.Write))
  55. {
  56. num++;
  57. Thread.Sleep();
  58. }
  59. Thread.Sleep();
  60. }
  61. });
  62. }
  63. }
  64.  
  65. /// <summary>
  66. /// 排他锁工具类
  67. /// </summary>
  68. public class MonitorUtil
  69. {
  70. /// <summary>
  71. /// 自定义锁对象
  72. /// </summary>
  73. internal class CustMonitor : IDisposable
  74. {
  75. /// <summary>
  76. /// 锁对象
  77. /// </summary>
  78. private Object lockObj = null;
  79.  
  80. /// <summary>
  81. /// 构造函数
  82. /// </summary>
  83. /// <param name="lockObj">锁对象</param>
  84. public CustMonitor(Object lockObj)
  85. {
  86. this.lockObj = lockObj;
  87. }
  88.  
  89. /// <summary>
  90. /// 锁释放
  91. /// </summary>
  92. public void Dispose()
  93. {
  94. try
  95. {
  96. Monitor.Exit(this.lockObj);
  97. }
  98. catch
  99. {
  100. // 当前线程如果没有获取到锁时,则会抛出异常。此处直接吞掉
  101. }
  102. }
  103. }
  104.  
  105. /// <summary>
  106. /// 锁信息
  107. /// </summary>
  108. internal class LockInfo
  109. {
  110. /// <summary>
  111. /// 构造函数
  112. /// </summary>
  113. /// <param name="lockObj">锁实例</param>
  114. /// <param name="custMonitor">自定义锁对象</param>
  115. public LockInfo(Object lockObj, CustMonitor custMonitor)
  116. {
  117. this.CustMonitor = custMonitor;
  118. this.LockObj = lockObj;
  119. }
  120.  
  121. /// <summary>
  122. /// 自定义锁对象
  123. /// </summary>
  124. public CustMonitor CustMonitor { get; private set; }
  125.  
  126. /// <summary>
  127. /// 锁实例
  128. /// </summary>
  129. public Object LockObj { get; private set; }
  130. }
  131.  
  132. /// <summary>
  133. /// 锁集合
  134. /// </summary>
  135. private ConcurrentDictionary<String, LockInfo> lockObjData = new ConcurrentDictionary<String, LockInfo>();
  136.  
  137. /// <summary>
  138. /// lockObjData同步对象
  139. /// </summary>
  140. private Object custLockObj = new Object();
  141.  
  142. /// <summary>
  143. /// 获取锁对象
  144. /// </summary>
  145. /// <param name="lockName">返回锁对象</param>
  146. /// <param name="waitTime">等待时间(单位:毫秒)</param>
  147. /// <returns>返回锁对象</returns>
  148. /// <exception cref="TimeoutException">获取锁对象超时时,抛出此异常</exception>
  149. public IDisposable GetLock(String lockName, Int32 waitTime = )
  150. {
  151. // 获取锁对象
  152. var lockObj = GetLockInfo(lockName);
  153.  
  154. // 规范等待时间长
  155. if (waitTime <= )
  156. {
  157. // 进入锁
  158. Monitor.Enter(lockObj.LockObj);
  159. }
  160. else
  161. {
  162. // 进入锁
  163. if (Monitor.TryEnter(lockObj.LockObj, waitTime) == false)
  164. {
  165. return lockObj.CustMonitor;
  166. //throw new TimeoutException("等待锁超时");
  167. }
  168. }
  169.  
  170. return lockObj.CustMonitor;
  171. }
  172.  
  173. /// <summary>
  174. /// 获取锁对象信息
  175. /// </summary>
  176. /// <param name="lockName">锁名称</param>
  177. /// <returns>返回锁对象</returns>
  178. private LockInfo GetLockInfo(String lockName)
  179. {
  180. LockInfo lockObj = null;
  181.  
  182. // 懒汉方式,先获取一次锁对象
  183. if (lockObjData.ContainsKey(lockName))
  184. {
  185. lockObj = lockObjData[lockName];
  186. }
  187. else
  188. {
  189. lock (custLockObj)
  190. {
  191. if (lockObjData.ContainsKey(lockName))
  192. {
  193. lockObj = lockObjData[lockName];
  194. }
  195. else
  196. {
  197. // 如果获取不到锁,则创建一个锁对象
  198.  
  199. var lockInstance = new Object();
  200. lockObj = new LockInfo(lockInstance, new CustMonitor(lockInstance));
  201.  
  202. lockObjData[lockName] = lockObj;
  203. }
  204. }
  205. }
  206.  
  207. return lockObj;
  208. }
  209. }
  210.  
  211. /// <summary>
  212. /// 读写锁工具类
  213. /// </summary>
  214. public class ReadWriteLockUtil
  215. {
  216. /// <summary>
  217. /// 自定义锁对象
  218. /// </summary>
  219. internal class CustMonitor : IDisposable
  220. {
  221. /// <summary>
  222. /// 获取方式
  223. /// </summary>
  224. private ReadWriteEnum getType;
  225.  
  226. /// <summary>
  227. /// 锁对象
  228. /// </summary>
  229. private ReaderWriterLockSlim lockObj = null;
  230.  
  231. /// <summary>
  232. /// 构造函数
  233. /// </summary>
  234. /// <param name="lockObj">锁对象</param>
  235. /// <param name="getType">获取方式</param>
  236. public CustMonitor(ReaderWriterLockSlim lockObj, ReadWriteEnum getType)
  237. {
  238. this.lockObj = lockObj;
  239. this.getType = getType;
  240. }
  241.  
  242. /// <summary>
  243. /// 锁释放
  244. /// </summary>
  245. public void Dispose()
  246. {
  247. if (getType == ReadWriteEnum.Read && lockObj.IsReadLockHeld)
  248. {
  249. lockObj.ExitReadLock();
  250. }
  251. else if (getType == ReadWriteEnum.Write && lockObj.IsWriteLockHeld)
  252. {
  253. lockObj.ExitWriteLock();
  254. }
  255. }
  256. }
  257.  
  258. /// <summary>
  259. /// 读写枚举
  260. /// </summary>
  261. public enum ReadWriteEnum
  262. {
  263. /// <summary>
  264. /// 读
  265. /// </summary>
  266. Read,
  267.  
  268. /// <summary>
  269. /// 写
  270. /// </summary>
  271. Write
  272. }
  273.  
  274. /// <summary>
  275. /// 锁集合
  276. /// </summary>
  277. private ConcurrentDictionary<String, ReaderWriterLockSlim> lockObjData = new ConcurrentDictionary<String, ReaderWriterLockSlim>();
  278.  
  279. /// <summary>
  280. /// lockObjData同步对象
  281. /// </summary>
  282. private Object custLockObj = new Object();
  283.  
  284. /// <summary>
  285. /// 获取锁对象
  286. /// </summary>
  287. /// <param name="lockName">返回锁对象</param>
  288. /// <param name="getType">获取方式</param>
  289. /// <param name="waitTime">等待时间(单位:毫秒),大于0,则等待指定时间,非正数,则死等</param>
  290. /// <returns>返回锁对象</returns>
  291. /// <exception cref="TimeoutException">获取锁对象超时时,抛出此异常</exception>
  292. public IDisposable GetLock(String lockName, ReadWriteEnum getType, Int32 waitTime = )
  293. {
  294. // 获取锁对象
  295. var lockInfo = GetLockInfo(lockName);
  296.  
  297. // 规范等待时间长
  298. if (waitTime <= )
  299. {
  300. // 进入锁
  301. return GetLockByInfiniteWait(lockName, getType);
  302. }
  303.  
  304. // 进入锁
  305. if (getType == ReadWriteEnum.Read)
  306. {
  307. if (lockInfo.IsReadLockHeld || lockInfo.TryEnterReadLock(waitTime))
  308. {
  309. return new CustMonitor(lockInfo, getType);
  310. }
  311.  
  312. throw new TimeoutException("等待读锁超时");
  313. }
  314. else if (getType == ReadWriteEnum.Write)
  315. {
  316. if (lockInfo.IsWriteLockHeld || lockInfo.TryEnterWriteLock(waitTime))
  317. {
  318. return new CustMonitor(lockInfo, getType);
  319. }
  320.  
  321. throw new TimeoutException("等待写锁超时");
  322. }
  323.  
  324. return null;
  325. }
  326.  
  327. /// <summary>
  328. /// 获取锁对象,获取过程会死等。直到获取到锁对象
  329. /// </summary>
  330. /// <param name="lockName">锁名称</param>
  331. /// <param name="getType">获取方式</param>
  332. /// <returns>返回锁对象</returns>
  333. private IDisposable GetLockByInfiniteWait(String lockName, ReadWriteEnum getType)
  334. {
  335. // 获取锁对象
  336. var lockObj = GetLockInfo(lockName);
  337.  
  338. // 进入锁
  339. if (getType == ReadWriteEnum.Read)
  340. {
  341. lockObj.EnterReadLock();
  342.  
  343. return new CustMonitor(lockObj, getType);
  344. }
  345. else if (getType == ReadWriteEnum.Write)
  346. {
  347. lockObj.EnterWriteLock();
  348.  
  349. return new CustMonitor(lockObj, getType);
  350. }
  351.  
  352. return null;
  353. }
  354.  
  355. /// <summary>
  356. /// 获取锁对象信息
  357. /// </summary>
  358. /// <param name="lockName">锁名称</param>
  359. /// <returns>返回锁对象</returns>
  360. private ReaderWriterLockSlim GetLockInfo(String lockName)
  361. {
  362. ReaderWriterLockSlim lockObj = null;
  363.  
  364. // 懒汉方式,先获取一次锁对象
  365. if (lockObjData.ContainsKey(lockName))
  366. {
  367. lockObj = lockObjData[lockName];
  368. }
  369. else
  370. {
  371. lock (custLockObj)
  372. {
  373. if (lockObjData.ContainsKey(lockName))
  374. {
  375. lockObj = lockObjData[lockName];
  376. }
  377. else
  378. {
  379. // 如果获取不到锁,则创建一个锁对象
  380. lockObj = new ReaderWriterLockSlim();
  381. lockObjData[lockName] = lockObj;
  382. }
  383. }
  384. }
  385.  
  386. return lockObj;
  387. }
  388. }

锁的封装 读写锁、lock的更多相关文章

  1. Linux 自旋锁,互斥量(互斥锁),读写锁

    自旋锁(Spin Lock) 自旋锁类似于互斥量,不过自旋锁不是通过休眠阻塞进程,而是在取得锁之前一直处于忙等待的阻塞状态.这个忙等的阻塞状态,也叫做自旋. 自旋锁通常作为底层原语实现其他类型的锁. ...

  2. 多线程并发编程之显示锁ReentrantLock和读写锁

    在Java5.0之前,只有synchronized(内置锁)和volatile. Java5.0后引入了显示锁ReentrantLock. ReentrantLock概况 ReentrantLock是 ...

  3. Go基础系列:互斥锁Mutex和读写锁RWMutex用法详述

    sync.Mutex Go中使用sync.Mutex类型实现mutex(排他锁.互斥锁).在源代码的sync/mutex.go文件中,有如下定义: // A Mutex is a mutual exc ...

  4. Spring data Jpa,Mybatis,读写锁,@Lock 使用

    Spring data jpa 支持注解式的读写锁(悲观锁),实际上这个东西硬编码也简单,但是基于Jpa 命名方式定义的Sql,只能用注解添加支持读写锁了, 不了解读写锁的可以点这里 mysql读写锁 ...

  5. JUC——线程同步锁(ReentrantReadWriteLock读写锁)

    读写锁简介 所谓的读写锁值得是两把锁,在进行数据写入的时候有一个把“写锁”,而在进行数据读取的时候有一把“读锁”. 写锁会实现线程安全同步处理操作,而读锁可以被多个对象读取获取. 读写锁:ReadWr ...

  6. 架构师养成记--14.重入锁ReentrantLock 和 读写锁 ReentrantReadWriteLock

    ReentrantLock 有嗅探锁定和多路分支等功能,其实就是synchronized,wait,notify的升级. this锁定当前对象不方便,于是就有了用new Object()来作为锁的解决 ...

  7. Go 互斥锁(sync.Mutex)和 读写锁(sync.RWMutex)

    什么时候需要用到锁? 当程序中就一个线程的时候,是不需要加锁的,但是通常实际的代码不会只是单线程,所以这个时候就需要用到锁了,那么关于锁的使用场景主要涉及到哪些呢? 多个线程在读相同的数据时 多个线程 ...

  8. 从自旋锁、睡眠锁、读写锁到 Linux RCU 机制讲解

    ​    同步自我的 csdn 博客 6.S081 从自旋锁.睡眠锁.读写锁到 Linux RCU 机制讲解_我说我谁呢 --CSDN博客 总结一下 O/S 课程里面和锁相关的内容. 本文是 6.S0 ...

  9. JAVA线程锁-读写锁

    JAVA线程锁,除Lock的传统锁,又有两种特殊锁,叫读写锁ReadWriteLock 其中多个读锁不互斥,读锁和写锁互斥,写锁和写锁互斥 例子: /** * java线程锁分为读写锁 ReadWri ...

随机推荐

  1. Scala学习笔记之伴生对象

    所谓伴生对象, 也是一个Scala中的单例对象, 使用object关键字修饰. 除此之外, 还有一个使用class关键字定义的同名类, 这个类和单例对象存在于同一个文件中, 这个类就叫做这个单例对象的 ...

  2. centos环境自动化批量安装软件脚本

    自动化安装jdk软件部署脚本 准备工作: 1.在执行脚本的服务器上生成免密码公钥: 安装expect命令 yum install -y expect ssh-keygen 三次回车 2.将jdk-7u ...

  3. Mac Aria2 使用Privoxy将socks代理转化为http代理

    安装Privoxy 打开终端安装privoxy来实现这里我是通过brew来进行的安装 brew install privoxy 看到这行已经安装成功 ==> Caveats To have la ...

  4. HTTPS 和 HTTP

    https://www.zhihu.com/question/52790301

  5. NGUI缓动函数

    缓动函数:http://easings.net/zh-cn 研究NGUI的博客:http://dsqiu.iteye.com/category/295721

  6. VBA 小知识

    1. 循环 Dim i As Integer 'body Next 'body Wend 2. 键值数据结构 'create dictionary object Set dictMembers = C ...

  7. Host 'XXX' is not allowed to connect to this MySQL server 解决方案/如何开启MySQL的远程帐号

    www.cnblogs.com/zhangzhu/archive/2013/08/22/3274831.html 如何开启MySQL的远程帐号-1)首先以 root 帐户登陆 MySQL 在 Wind ...

  8. String类的常用判断方法使用练习

    选取了一些常用的判断方法进行了使用练习,后续跟新其他方法 package StringDemo; // String类的判断方法解析 // 1:boolean equals(); // 判断字符串是否 ...

  9. SQL Server创建复合索引时,复合索引列顺序对查询的性能影响

    说说复合索引 写索引的博客太多了,一直不想动手写,有一下两个原因:一是觉得有炒剩饭的嫌疑,有兄弟曾说:索引吗,只要在查询条件上建索引就行了,真的可以这么暴力吗?二来觉得,索引是个非常大的话题,很难概括 ...

  10. C#获得客户端IP

    代码: /// <summary> /// 获得当前页面客户端的IP /// </summary> /// <returns>当前页面客户端的IP</retu ...