Cache+多线程下内存失效的一个bug

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判断
这个几率不大于百万分之一

但是上周末确实就出现了...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值