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

  class Program
{
static void Main(string[] args)
{
ReadWriteUtilTest();
MonitorUtilTest();
Console.ReadLine();
}
private static void MonitorUtilTest()
{
MonitorUtil util = new MonitorUtil();
int num = ;
for (int index = ; index < ; index++)
{
var th = new Thread(new ThreadStart(() =>
{
Thread.Sleep();
for (int i = ; i < ; i++)
{
using (util.GetLock("hello"))
{
num++;
Console.WriteLine("num={0}", num);
}
}
})); th.Start();
}
} private static void ReadWriteUtilTest()
{
ReadWriteLockUtil utl = new ReadWriteLockUtil();
Int32 num = ;
for (var i = ; i < ; i++)
{
Task.Factory.StartNew(() =>
{
while (true)
{
using (utl.GetLock("hello", ReadWriteLockUtil.ReadWriteEnum.Read))
{
Console.WriteLine("num={0}", num);
Thread.Sleep();
}
}
});
}
Task.Factory.StartNew(() =>
{
while (true)
{
using (utl.GetLock("hello", ReadWriteLockUtil.ReadWriteEnum.Write))
{
num++;
Thread.Sleep();
}
Thread.Sleep();
}
});
}
} /// <summary>
/// 排他锁工具类
/// </summary>
public class MonitorUtil
{
/// <summary>
/// 自定义锁对象
/// </summary>
internal class CustMonitor : IDisposable
{
/// <summary>
/// 锁对象
/// </summary>
private Object lockObj = null; /// <summary>
/// 构造函数
/// </summary>
/// <param name="lockObj">锁对象</param>
public CustMonitor(Object lockObj)
{
this.lockObj = lockObj;
} /// <summary>
/// 锁释放
/// </summary>
public void Dispose()
{
try
{
Monitor.Exit(this.lockObj);
}
catch
{
// 当前线程如果没有获取到锁时,则会抛出异常。此处直接吞掉
}
}
} /// <summary>
/// 锁信息
/// </summary>
internal class LockInfo
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="lockObj">锁实例</param>
/// <param name="custMonitor">自定义锁对象</param>
public LockInfo(Object lockObj, CustMonitor custMonitor)
{
this.CustMonitor = custMonitor;
this.LockObj = lockObj;
} /// <summary>
/// 自定义锁对象
/// </summary>
public CustMonitor CustMonitor { get; private set; } /// <summary>
/// 锁实例
/// </summary>
public Object LockObj { get; private set; }
} /// <summary>
/// 锁集合
/// </summary>
private ConcurrentDictionary<String, LockInfo> lockObjData = new ConcurrentDictionary<String, LockInfo>(); /// <summary>
/// lockObjData同步对象
/// </summary>
private Object custLockObj = new Object(); /// <summary>
/// 获取锁对象
/// </summary>
/// <param name="lockName">返回锁对象</param>
/// <param name="waitTime">等待时间(单位:毫秒)</param>
/// <returns>返回锁对象</returns>
/// <exception cref="TimeoutException">获取锁对象超时时,抛出此异常</exception>
public IDisposable GetLock(String lockName, Int32 waitTime = )
{
// 获取锁对象
var lockObj = GetLockInfo(lockName); // 规范等待时间长
if (waitTime <= )
{
// 进入锁
Monitor.Enter(lockObj.LockObj);
}
else
{
// 进入锁
if (Monitor.TryEnter(lockObj.LockObj, waitTime) == false)
{
return lockObj.CustMonitor;
//throw new TimeoutException("等待锁超时");
}
} return lockObj.CustMonitor;
} /// <summary>
/// 获取锁对象信息
/// </summary>
/// <param name="lockName">锁名称</param>
/// <returns>返回锁对象</returns>
private LockInfo GetLockInfo(String lockName)
{
LockInfo lockObj = null; // 懒汉方式,先获取一次锁对象
if (lockObjData.ContainsKey(lockName))
{
lockObj = lockObjData[lockName];
}
else
{
lock (custLockObj)
{
if (lockObjData.ContainsKey(lockName))
{
lockObj = lockObjData[lockName];
}
else
{
// 如果获取不到锁,则创建一个锁对象 var lockInstance = new Object();
lockObj = new LockInfo(lockInstance, new CustMonitor(lockInstance)); lockObjData[lockName] = lockObj;
}
}
} return lockObj;
}
} /// <summary>
/// 读写锁工具类
/// </summary>
public class ReadWriteLockUtil
{
/// <summary>
/// 自定义锁对象
/// </summary>
internal class CustMonitor : IDisposable
{
/// <summary>
/// 获取方式
/// </summary>
private ReadWriteEnum getType; /// <summary>
/// 锁对象
/// </summary>
private ReaderWriterLockSlim lockObj = null; /// <summary>
/// 构造函数
/// </summary>
/// <param name="lockObj">锁对象</param>
/// <param name="getType">获取方式</param>
public CustMonitor(ReaderWriterLockSlim lockObj, ReadWriteEnum getType)
{
this.lockObj = lockObj;
this.getType = getType;
} /// <summary>
/// 锁释放
/// </summary>
public void Dispose()
{
if (getType == ReadWriteEnum.Read && lockObj.IsReadLockHeld)
{
lockObj.ExitReadLock();
}
else if (getType == ReadWriteEnum.Write && lockObj.IsWriteLockHeld)
{
lockObj.ExitWriteLock();
}
}
} /// <summary>
/// 读写枚举
/// </summary>
public enum ReadWriteEnum
{
/// <summary>
/// 读
/// </summary>
Read, /// <summary>
/// 写
/// </summary>
Write
} /// <summary>
/// 锁集合
/// </summary>
private ConcurrentDictionary<String, ReaderWriterLockSlim> lockObjData = new ConcurrentDictionary<String, ReaderWriterLockSlim>(); /// <summary>
/// lockObjData同步对象
/// </summary>
private Object custLockObj = new Object(); /// <summary>
/// 获取锁对象
/// </summary>
/// <param name="lockName">返回锁对象</param>
/// <param name="getType">获取方式</param>
/// <param name="waitTime">等待时间(单位:毫秒),大于0,则等待指定时间,非正数,则死等</param>
/// <returns>返回锁对象</returns>
/// <exception cref="TimeoutException">获取锁对象超时时,抛出此异常</exception>
public IDisposable GetLock(String lockName, ReadWriteEnum getType, Int32 waitTime = )
{
// 获取锁对象
var lockInfo = GetLockInfo(lockName); // 规范等待时间长
if (waitTime <= )
{
// 进入锁
return GetLockByInfiniteWait(lockName, getType);
} // 进入锁
if (getType == ReadWriteEnum.Read)
{
if (lockInfo.IsReadLockHeld || lockInfo.TryEnterReadLock(waitTime))
{
return new CustMonitor(lockInfo, getType);
} throw new TimeoutException("等待读锁超时");
}
else if (getType == ReadWriteEnum.Write)
{
if (lockInfo.IsWriteLockHeld || lockInfo.TryEnterWriteLock(waitTime))
{
return new CustMonitor(lockInfo, getType);
} throw new TimeoutException("等待写锁超时");
} return null;
} /// <summary>
/// 获取锁对象,获取过程会死等。直到获取到锁对象
/// </summary>
/// <param name="lockName">锁名称</param>
/// <param name="getType">获取方式</param>
/// <returns>返回锁对象</returns>
private IDisposable GetLockByInfiniteWait(String lockName, ReadWriteEnum getType)
{
// 获取锁对象
var lockObj = GetLockInfo(lockName); // 进入锁
if (getType == ReadWriteEnum.Read)
{
lockObj.EnterReadLock(); return new CustMonitor(lockObj, getType);
}
else if (getType == ReadWriteEnum.Write)
{
lockObj.EnterWriteLock(); return new CustMonitor(lockObj, getType);
} return null;
} /// <summary>
/// 获取锁对象信息
/// </summary>
/// <param name="lockName">锁名称</param>
/// <returns>返回锁对象</returns>
private ReaderWriterLockSlim GetLockInfo(String lockName)
{
ReaderWriterLockSlim lockObj = null; // 懒汉方式,先获取一次锁对象
if (lockObjData.ContainsKey(lockName))
{
lockObj = lockObjData[lockName];
}
else
{
lock (custLockObj)
{
if (lockObjData.ContainsKey(lockName))
{
lockObj = lockObjData[lockName];
}
else
{
// 如果获取不到锁,则创建一个锁对象
lockObj = new ReaderWriterLockSlim();
lockObjData[lockName] = lockObj;
}
}
} return lockObj;
}
}

锁的封装 读写锁、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. 巧用vsprintf将浮点数等转化字符串

    直接上代码 #include <stdarg.h> ]; int vspf(char *fmt, ...) { va_list argptr; int cnt; va_start(argp ...

  2. mybatis - resultMap

    resultMap有比较强大的自动映射,下面是摘自mybatis中文官网的的片段: 当自动映射查询结果时,MyBatis会获取sql返回的列名并在java类中查找相同名字的属性(忽略大小写). 这意味 ...

  3. 【转】Selenium 面试题总结(乙醇Blog记录的面试题)

    原文链接:http://www.cnblogs.com/tsbc/p/4922368.html ###selenium中如何判断元素是否存在? - isElementPresent   ###sele ...

  4. jquery仿淘宝规格颜色选择效果

    jquery实现的仿淘宝规格颜色选择效果源代码如下 jquery仿淘宝规格颜色选择效果 -收缩HTML代码 运行代码 [如果运行无效果,请自行将源代码保存为html文件运行] <script t ...

  5. LinQ的组合+分页

    前台代码: 名称:<asp:TextBox ID="Textname" runat="server"></asp:TextBox> 油耗 ...

  6. UNIX域套接字(unix domain)

    UNIX域套接字用于在同一台机器上运行的进程之间的通信. UNIX域套接字提供流和数据报两种接口. 说明:UNIX域套接字比因特网套接字效率更高.它仅赋值数据:不进行协议处理,如添加或删除网络报头.计 ...

  7. IIS7.5 webapi 不支持 Delete、Put 解决方法

    在IIS管理界面选择API的项目,选择 “Features View”. 2.  选择 “Handler Mappings” 菜单. 3. 打开“WebDAV” 选项. 4. 点击 “Request ...

  8. 假装这些是MyEclipse的快捷键(1)

    Java快捷键 Alt + / 代码自动补全Alt + Shift + S 功能菜单 Ctrl + 1 代码自动修正Ctrl + / 单行注释/取消Ctrl + O 查看类的所有方法Ctrl + T ...

  9. html+css 技巧

    3.css定义的技巧:[1].为了将来的css代码优化,建议所有的属性上要带上“:” [2].某些html 标签,有自己默认的css属性值,       例如h1 标签就有自己的属性值,自动就是加粗显 ...

  10. My97 设置近3天日期

    1.引用my97 js 和css 2.前台代码 <div class="FormItem"> <label> 申请时间</label> < ...