我有一个缓存对象缓存,所述缓存可以容纳多个类型,并且每当给定{T}被访问时,我都想对所述{T}添加一个锁。
我的实施:
readonly static IDictionary<Type, List<object>> _cache = new ConcurrentDictionary<Type, List<object>>();
private static List<object> FindTypeInCache(Type type)
{
List<object> list;
if (_cache.TryGetValue(type, out list))
{
return list;
}
else
{
_cache[type] = new List<object>();
}
return new List<object>();
}
public static T FindFirstBy<T>(Func<T, bool> predicate) where T : class
{
// Is this a valid lock locking only _cache[T] ? And not _cache as whole?
lock (_cache[typeof(T)])
{
return FindTypeInCache(typeof(T)).Cast<T>().Where(predicate).FirstOrDefault();
}
}
public static bool AddOrUpdate<T>(Func<T, bool> predicate, T entity) where T : class
{
lock (_cache[typeof(T)])
{
// Find Type cache.
List<object> list = FindTypeInCache(typeof(T));
// Look for old entity.
var e = list.Cast<T>().Where(predicate).FirstOrDefault();
// If no old record exists no problem we treat this as if its a new record.
if (e != null)
{
// Old record found removing it.
list.Remove(e);
}
// Regardless if object existed or not we add it to our Cache.
list.Add(entity);
_cache[typeof(T)] = list;
}
}在访问时,我的实现是否只正确地锁定了_cacheT,而不是整个_cache作为一个整体?
发布于 2015-06-15 08:14:36
你的代码有很多奇怪(或完全错误)的地方。
首先,您使用的是ConcurrentDictionary,但不是将其用作并发字典。例如,要初始化列表,可以使用GetOrAddMethod
private static List<object> FindTypeInCache(Type type)
{
return _cache.GetOrAdd(type, () => new List<object>());
}简单和线程安全:)
其次,您正在锁定_cache[type] --但是即使缓存中没有这样的类型。这意味着一个KeyNotFoundException。
第三,使用锁保护的唯一代码是读取。但这很可能还不够--至少,您还需要使用相同的锁来保护写入(特别是考虑到上面的点),并且取决于返回值的实际用法,返回值的突变(如果它确实是可变的,也可以读取该可变值)。
换句话说,您只保护了实际上不需要保护的代码(如果您使用正确的方法更新字典)!围绕lock等的额外Where可能会稍微有所帮助,但它肯定不能保证List访问的安全性。
所有这一切,也许有一个更好的解决办法。您使用的是使用通用方法的缓存。为什么不使缓存本身成为通用的呢?这样,首先您将避免使用字典,因为存储在字典中的每个泛型类型都将得到它们自己的类型--这也意味着您可以在静态构造函数中安全地初始化List<T>。任何锁定也可以安全地应用于对特定通用缓存的所有访问,而不是您现在拥有的“聚合”缓存。
https://stackoverflow.com/questions/30840178
复制相似问题