public class SynchronizedCache
{
private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();
/// <summary>
/// 同步缓存块维护的数据资源
/// </summary>
private Dictionary<int, string> innerCache = new Dictionary<int, string>();
/// <summary>
/// 同步缓存块维护的数据资源长度
/// </summary>
public int Count
{
get { return innerCache.Count; }
}
/// <summary>
/// 线程安全的添加操作
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public void Add(int key,string value)
{
//尝试进入写入模式锁定状态
cacheLock.EnterWriteLock();
try
{
innerCache.Add(key, value);
}
finally
{
//退出写入模式锁定状态
cacheLock.ExitWriteLock();
}
}
/// <summary>
/// 带锁超时的添加的操作
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="timeout"></param>
/// <returns></returns>
public bool AddWithTimeout(int key, string value, int timeout)
{
if (cacheLock.TryEnterWriteLock(timeout))
{
try
{
innerCache.Add(key, value);
}
finally
{
cacheLock.ExitWriteLock();
}
return true;
}
else
{
return false;
}
}
/// <summary>
/// 线程安全的读取操作
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public string Read(int key)
{
cacheLock.EnterReadLock();
try
{
return innerCache[key];
}
finally
{
cacheLock.ExitReadLock();
}
}
/// <summary>
/// 线程安全的添加修改操作
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public AddOrUpdateStatus AddOrUpdate(int key, string value)
{
cacheLock.EnterUpgradeableReadLock();
try
{
string result = null;
if (innerCache.TryGetValue(key, out result))
{
if (result == value)
{
return AddOrUpdateStatus.Unchanged;
}
else
{
cacheLock.EnterWriteLock();
try
{
innerCache[key] = value;
}
finally
{
cacheLock.ExitWriteLock();
}
return AddOrUpdateStatus.Updated;
}
}
else
{
cacheLock.EnterWriteLock();
try
{
innerCache.Add(key, value);
}
finally
{
cacheLock.ExitWriteLock();
}
return AddOrUpdateStatus.Added;
}
}
finally
{
cacheLock.ExitUpgradeableReadLock();
}
}
/// <summary>
/// 线程安全的删除操作
/// </summary>
/// <param name="key"></param>
public void Delete(int key)
{
cacheLock.EnterWriteLock();
try
{
innerCache.Remove(key);
}
finally
{
cacheLock.ExitWriteLock();
}
}
/// <summary>
/// 添加或修改时产生的状态
/// </summary>
public enum AddOrUpdateStatus
{
Added,
Updated,
Unchanged
};
/// <summary>
/// 析构 释放资源
/// </summary>
~SynchronizedCache()
{
if (cacheLock != null) cacheLock.Dispose();
}
}
- 为什么不能使用 EnterReadLock
EnterReadLock 是一种只读锁,它允许多个线程同时进入读取状态,但不允许写入。如果在读取过程中发现需要写入(例如更新缓存或添加新键值对),则需要升级为写锁。然而,EnterReadLock 无法直接升级为写锁,必须先释放读锁,再获取写锁。这会导致以下问题:
线程安全问题:在释放读锁和获取写锁的间隙,其他线程可能会修改缓存,导致数据不一致。
性能问题:频繁地释放读锁和获取写锁会增加锁的开销,降低性能。
- 为什么使用 EnterUpgradeableReadLock
EnterUpgradeableReadLock 是一种可升级的读锁,它允许线程在读取时保持锁,并在需要时直接升级为写锁。这种锁机制的优点包括:
线程安全:在升级过程中,其他线程无法获取写锁,从而保证了数据的一致性。
性能优化:减少了锁的切换次数,避免了频繁释放和获取锁的开销。
逻辑清晰:代码逻辑更加简洁,避免了复杂的锁释放和获取操作。