public static class MessageType2TemplateService
{
private static Dictionary<int, HtmlTemplateModel> list = new Dictionary<int, HtmlTemplateModel>();
private static HtmlTemplateDAL dao = new HtmlTemplateDAL();
public static HtmlTemplateModel getTemplate(int messageType)
{
try
{
StopWatcher sw = new StopWatcher();
lock (list)
{
if (HttpRuntime.Cache["HtmlTemplateListHashByMessageType"] == null)
{
sw.start();
list.Clear();
HtmlTemplateModel model=new HtmlTemplateModel();
model.PageSize=int.MaxValue;
model.CurPage=1;
IList<HtmlTemplateModel> templateList = dao.GetHtmlTemplateList(model);
if (templateList.Count > 0)
{
foreach (HtmlTemplateModel item in templateList)
{
if (item.MessageType == null)
{
continue;
}
item.TemplateHtml = string.Empty;
list.Add((int)item.MessageType, item);
}
}
HttpRuntime.Cache.Add("HtmlTemplateListHashByMessageType", list, null, DateTime.Now.AddMinutes(20), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
sw.stop();
EdmLogger.LogProcess("获取所有模板", sw.getTime());
}
else
{
list = (Dictionary<int, HtmlTemplateModel>)HttpRuntime.Cache["HtmlTemplateListHashByMessageType"];
}
}
if (list.ContainsKey(messageType))
{
return list[messageType];
}
else
{
throw new Exception("没有messageType对应的模板");
}
}
catch (Exception ex)
{
EdmLogger.LogError("根据messageType获取模板错误", ex);
throw ex;
}
}
}
这里是在多线程下的一个静态类
用于根据messageType获取模板
然后这些模板会保存在cache里面
同样的模板会保存两份
一份在cache一份在Dictionary里面
其实在这个场景里面cache只起到了定时器的作用,只是因为沿用以前的规范用了cache
然后这个周末就爆出了一个bug
list变成null然后程序报空指针引用的bug
拿到程序分析了下
确实存在这样一个bug:
lock(list)判断缓存是否为空的时候缓存不为空
但是当到else里面让list引用缓存的时候缓存却因为设定的过期时间到期变为null
于是list就变为了null
于是下一次调用的时候在lock(list)的时候就会报出空指针引用的错误
当然这种情况很少见,只有极其微小的概率
因为必须要时间刚好卡在过期的时间前的一瞬间在处理那个if判断
这个几率不大于百万分之一
但是上周末确实就出现了...