最近由于项目上面建议使用读写锁,而去除常见的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 = 0; for (int index = 0; index < 20; index++) { var th = new Thread(new ThreadStart(() => { Thread.Sleep(100); for (int i = 0; i < 100; i++) { using (util.GetLock("hello")) { num++; Console.WriteLine("num={0}", num); } } })); th.Start(); } } private static void ReadWriteUtilTest() { ReadWriteLockUtil utl = new ReadWriteLockUtil(); Int32 num = 0; for (var i = 0; i < 10; i++) { Task.Factory.StartNew(() => { while (true) { using (utl.GetLock("hello", ReadWriteLockUtil.ReadWriteEnum.Read)) { Console.WriteLine("num={0}", num); Thread.Sleep(1000); } } }); } Task.Factory.StartNew(() => { while (true) { using (utl.GetLock("hello", ReadWriteLockUtil.ReadWriteEnum.Write)) { num++; Thread.Sleep(5000); } Thread.Sleep(5000); } }); } } /// <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 = 10) { // 获取锁对象 var lockObj = GetLockInfo(lockName); // 规范等待时间长 if (waitTime <= 0) { // 进入锁 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 = 10000) { // 获取锁对象 var lockInfo = GetLockInfo(lockName); // 规范等待时间长 if (waitTime <= 0) { // 进入锁 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; } }