84年的矿泉水

博客园 首页 新随笔 联系 订阅 管理
  83 随笔 :: 0 文章 :: 645 评论 :: 17万 阅读

  刚刚被一同事叫去看一个问题,问题的表象是程序会周期性的报“集合被修改,循环无法继续”的异常,查了半天的问题,最后找到问题如下:

     因为本地缓存很少过期,所以我们就将本地的缓存全部放入hashtable中,而hashtable中的value一般情况下就是IList<T>类型,而hashtable中的数据也不是一定不过期,所以我们就增加了缓存的更新功能,好了,问题出现了。

  代码大致是这样的

      private readonly static hashtable ht = hashtable.sync(new hashtable());

      public static hashtable Cache{return ht;};

      这个代码是在我们的缓存类中的,下面的代码是引用的地方:

     IList<T> list = Cache["key"] as IList<T>;

     foreach(T obj in list)

  {

          do somthing;

  }

     看看代码,好像没有你问题,但是真的运行起来就不是那么一回事情了。

     这里的问题出在我们的一个思维定势。ht是线程安全的,但是ht中value不一定,这是主因。从代码中可以看出来,value存放是IList,那么存放的应该是引用(也就是指针),而当我们通过索引器得到这个IList时,这部操作是线程安全的,但是到这里的安全并不意味着foreach也是安全的。因为hashtable提供的线程安全功能已经完成了,foreach已经是在脱离了hashtable的线程安全运行的。所以问题就会出现了。IList是引用类型,所以我们foreach的Ilist只是一个指针,具体的值存放在IList指针指向的地方,而当我们正好在更新hashtable中的foreach中指定的那个IList的时候,这个IList的指针变改变了,所以就会报错;

     解决问题的办法就是增加一个结构体,这个结构体中有两个对象:

     struct Item{object locker;IList list;},这样,每次更新或者循环的时候都要先加上locker的锁,这样就可以避免了线程的我安全问题!

posted on   xvhfeng  阅读(4676)  评论(8编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
点击右上角即可分享
微信分享提示