Net中的并发锁

object _lock

锁的概念,这里不做详细阐述。先从最经典的应用场景来说,单例模式在不考虑静态构造函数实现的方式下,用锁实现是必须的。比如:

public class Singleton
{
private static Singleton _Singleton = null;
private static object Singleton_Lock = new object();
public static Singleton CreateInstance()
{
if (_Singleton == null)
{
lock (Singleton_Lock)
{
if (_Singleton == null)
{
_Singleton = new Singleton();
}
}
}
return _Singleton;
}
}

这里我们注意到

static object Singleton_Lock = new object()

这里的lock,其实是一个语法糖,具体定义就不多说,也不是本文的重点。简单说一下lock的注意事项
1. lock的对象必须是引用类型(string类型比较特殊,会被CLR‘暂留’,所以也不行)
2. lock推荐使用静态、私有、只读的对象。
3. 对于2中的只读,是需要保证在lock外无法修改。也补充了第一点中string类型不行的原因。
4. lock(this),如果无法保证外部及其他线程是否会访问,最好不要这样。因为可能会发生死锁。

综上,lock(readonly static referenceTypes)是最优雅的使用方式。

Net3.5中的ReaderWriterLockSlim

ReaderWriterLockSlim支持三种锁定模式
1. Read
2. Write
3. UpgradeableRead
这三种锁定模式所对应的方法分别是:
1. EnterReadLock
2. EnterWriteLock
3. EnterUpgradeableReadLock

其中,Read模式是共享锁定模式,任意线程都可以在此模式下同时获得锁。
Write模式是互斥模式,任意数量线程只允许一个线程进入该锁。

其实这篇博文的目的,就是为了测试传统Object_lock 和ReaderWriteLockSlim的性能差异。废话不多,实现上使用了赵姐夫的CodeTimer

测试代码如下:

public class MemoryCache<TKey, TValue>
{
private ConcurrentDictionary<TKey, TValue> _dicCache = new ConcurrentDictionary<TKey, TValue>();

private Dictionary<TKey, Lazy> _dicLazyValue = new Dictionary<TKey, Lazy>();

private ReaderWriterLockSlim _cacheLock = new ReaderWriterLockSlim();

private object _locker = new object();

public TValue GetValueByObjectLocker(TKey key, Lazy value)
{
if (!_dicLazyValue.ContainsKey(key))
{
lock (_locker)
{
if (!_dicLazyValue.ContainsKey(key))
{
_dicLazyValue.Add(key, value);
}
}
}
if (_dicCache == null)
{
lock (_locker)
{
if (_dicCache == null)
{
_dicCache = new ConcurrentDictionary<TKey, TValue>();
}
}
}
return _dicCache.GetOrAdd(key, _dicLazyValue[key].Value);
}

public TValue GetValueByLockSlim(TKey key, Lazy value)
{
if (!_dicLazyValue.ContainsKey(key))
{
try
{
_cacheLock.EnterWriteLock();
if (!_dicLazyValue.ContainsKey(key))
{
_dicLazyValue.Add(key, value);
}
}
finally
{
_cacheLock.ExitWriteLock();
}
}
if (_dicCache == null)
{
try
{
_cacheLock.EnterUpgradeableReadLock();
if (_dicCache == null)
{
_dicCache = new ConcurrentDictionary<TKey, TValue>();
}
}
finally
{
_cacheLock.ExitUpgradeableReadLock();
}
}
return _dicCache.GetOrAdd(key, _dicLazyValue[key].Value);
}
}

使用控制台应用程序

static void Main(string[] args)
{
MemoryCache<string, string> _memoryCache = new MemoryCache<string, string>();
CodeTimer.Initialize();
CodeTimer.Time("object lock", 1000, () =>
{
var lazyStr = new Lazy(() => Thread.CurrentThread.ManagedThreadId.ToString());
_memoryCache.GetValueByObjectLocker("123", lazyStr);
});

CodeTimer.Time("LockSlim", 1000, () =>
{
var lazyStr = new Lazy(() => Thread.CurrentThread.ManagedThreadId.ToString());
_memoryCache.GetValueByLockSlim("456", lazyStr);
});
System.Console.WriteLine("123");
System.Console.ReadLine();
}

结果:

object lock
Time Elapsed: 7ms
CPU Cycles: 6,414,332
Gen 0: 0
Gen 1: 0
Gen 2: 0

LockSlim
Time Elapsed: 1ms
CPU Cycles: 3,182,178
Gen 0: 0
Gen 1: 0
Gen 2: 0

综上,当下次有使用'锁'的时候,请优先考虑ReaderWriterLockSlim以获取更高的性能和更低的CPU Cycles.

posted @ 2019-09-26 10:19  YamatAmain  阅读(492)  评论(0)    收藏  举报