我正在使用以下代码,对我来说,似乎下面的代码不会发生竞争条件。或者仍然存在竞争条件的可能性?
List<Document> listFromCache = Cache[dataCacheName] as List<Document>;
if (listFromCache != null)
{
//do something with listFromCache. **IS IT POSSIBLE** that listFromCache is
//NULL here
}
else
{
List<Document> list = ABC.DataLayer.GetDocuments();
Cache.Insert(dataCacheName, list, null, DateTime.Now.AddMinutes(5),
System.Web.Caching.Cache.NoSlidingExpiration);
}
更新 克里斯帮助我解决了这个问题,但我想,我会分享一些对其他人非常有帮助的细节。
为了完全避免任何竞争条件,我必须在真实部分中添加一个检查,否则我最终会得到一个零计数的List,如果有人在Cache中清除它(不是删除该项目,而只是调用Clear在我的if评估为TRUE之后,在Cache中的List对象上的方法。那么,我在listFromCache对象中的if部分中没有任何数据。
要在我的原始代码中克服这种微妙的RACE条件,我必须在下面的代码中检查真实部分中的listFromCache,然后使用最新数据重新填充Cache。
另外,正如Chris所说,如果其他人通过调用Cache.Remove,方法从Cache中删除了这些项目,那么listFromCache就不会受到影响,因为垃圾收集器不会删除实际从HEAP内存中列出对象,因为名为'listFromCache'的变量仍然具有对它的引用(我在Chris的答案帖子中的评论中对此进行了更详细的解释)。
List<Document> listFromCache = Cache[dataCacheName] as List<Document>;
if (listFromCache != null)
{
//OVERCOME A SUBTLE RACE CONDITION BY IF BELOW
if( listFromCache == null || listFromCache.Count == 0)
{
List<Document> list = ABC.DataLayer.GetDocuments();
Cache.Insert(dataCacheName, list, null, DateTime.Now.AddMinutes(5),
System.Web.Caching.Cache.NoSlidingExpiration);
}
//NOW I AM SURE MY listFromCache contains true data
//do something with listFromCache. **IS IT POSSIBLE** that listFromCache is
//NULL here
}
else
{
List<Document> list = ABC.DataLayer.GetDocuments();
Cache.Insert(dataCacheName, list, null, DateTime.Now.AddMinutes(5),
System.Web.Caching.Cache.NoSlidingExpiration);
}
答案 0 :(得分:1)
不,您的评论中不可能listFromCache
将变为空,因为它是此时的本地参考。如果缓存条目在其他位置无效,则不会影响本地引用。但是,您可能会遇到检索空值的情况,但在收集文档(ABC.DataLayer.GetDocuments()
)的过程中,另一个进程已经这样做并插入了缓存条目,此时您将覆盖它。 (这可能是完全可以接受的,在这种情况下,太棒了!)
您可以尝试使用静态对象锁定它,但老实说,我不确定它是否可以在ASP.NET上下文中运行。我不记得Cache是否在所有ASP.NET进程(IIRC,具有不同的静态上下文)之间共享,或者只在每个单独的Web worker中共享。如果是后者,静态锁定将正常工作。
也是为了证明:
List<Document> listFromCache = Cache[dataCacheName] as List<Document>;
if (listFromCache != null)
{
Cache.Remove(dataCacheName);
//listFromCache will NOT be null here.
if (listFromCache != null)
{
Console.WriteLine("Not null!"); //this will run because it's not null
}
}