鎖的概念,這裏不作詳細闡述。先從最經典的應用場景來講,單例模式在不考慮靜態構造函數實現的方式下,用鎖實現是必須的。好比:html
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)是最優雅的使用方式。this
ReaderWriterLockSlim支持三種鎖定模式
1. Read
2. Write
3. UpgradeableRead
這三種鎖定模式所對應的方法分別是:
1. EnterReadLock
2. EnterWriteLock
3. EnterUpgradeableReadLock線程
其中,Read模式是共享鎖定模式,任意線程均可以在此模式下同時得到鎖。
Write模式是互斥模式,任意數量線程只容許一個線程進入該鎖。code
其實這篇博文的目的,就是爲了測試傳統Object_lock 和ReaderWriteLockSlim的性能差別。廢話很少,實現上使用了趙姐夫的CodeTimerhtm
測試代碼以下:對象
public class MemoryCache<TKey, TValue> { private ConcurrentDictionary<TKey, TValue> _dicCache = new ConcurrentDictionary<TKey, TValue>(); private Dictionary<TKey, Lazy<TValue>> _dicLazyValue = new Dictionary<TKey, Lazy<TValue>>(); private ReaderWriterLockSlim _cacheLock = new ReaderWriterLockSlim(); private object _locker = new object(); public TValue GetValueByObjectLocker(TKey key, Lazy<TValue> 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<TValue> 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); } }
使用控制檯應用程序blog
static void Main(string[] args) { MemoryCache<string, string> _memoryCache = new MemoryCache<string, string>(); CodeTimer.Initialize(); CodeTimer.Time("object lock", 1000, () => { var lazyStr = new Lazy<string>(() => Thread.CurrentThread.ManagedThreadId.ToString()); _memoryCache.GetValueByObjectLocker("123", lazyStr); }); CodeTimer.Time("LockSlim", 1000, () => { var lazyStr = new Lazy<string>(() => 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.