当系统中缓存访问热点集中,且其中某些key的缓存失效时间过短,导致大量的请求直接访问DB,从而在DB上产生很大的压力,遇到高并发情况下往往会导致系统崩溃。这种情况就被称为“缓存击穿”。
C#语言提供了一种避免缓存击穿的方法,就是使用lock
关键字,将可能产生高并发的代码块锁住,这样系统中只有一个线程能够访问这段代码,从而避免了缓存击穿的情况。
下面是使用lock
解决缓存击穿的完整流程:
- 判断缓存是否存在
- 如果是缓存命中,直接返回缓存值
- 如果缓存失效,立即上锁
- 判断缓存是否更新
- 如果缓存已更新,解锁并返回缓存值
- 如果缓存未更新,查询数据库获取新的数据,更新缓存并解锁
举两个实例说明:
示例1
private static readonly object CacheLock = new object();
public T GetObject<T>(string cacheKey, Func<T> getObjectFunc, TimeSpan expiresIn)
{
var cacheValue = MemoryCache.Default.Get(cacheKey);
if (cacheValue != null)
{
return (T)cacheValue;
}
lock (CacheLock) //上锁
{
//这里要再判断一遍,因为可能上一次请求已经获取了缓存
cacheValue = MemoryCache.Default.Get(cacheKey);
if (cacheValue != null)
{
return (T)cacheValue;
}
T result = getObjectFunc();
MemoryCache.Default.Add(cacheKey, result, DateTime.Now + expiresIn);
return result;
}
}
在这个方法中,我们使用lock
关键字将可能产生高并发的代码块锁住,这样就避免了多个线程同时操作缓存,导致缓存击穿的情况。
示例2
public static object GetLockObject(string key)
{
object value = CacheHelper.Get(key);
if(value != null)
{
return value;
}
lock (key)
{
value = CacheHelper.Get(key);
if(value != null)
{
return value;
}
value = new object();
CacheHelper.Add(key, value, TimeSpan.FromMinutes(30));
return value;
}
}
在这个方法中,我们使用lock
关键字将可能产生高并发的代码块锁住,这样就避免了多个线程同时操作缓存,导致缓存击穿的情况。这个方法中使用了一个额外的缓存GetLockObject()
返回一个唯一的锁对象,锁定整个关键字,避免了多个线程同时操作不同的锁对象,产生线程冲突。
综上所述,通过使用lock
关键字,我们可以有效地解决缓存击穿的问题,减少DB的压力,提高系统的并发能力。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:c# 如何用lock解决缓存击穿 - Python技术站