【原创】关于C#多线程安全问题的讨论

mac2022-06-30  25

在多线程编程中,很多地方都会碰到同时操作一个全局变量的问题,我们在操作过程中应该怎么避免发生混乱呢? 分下面几个方面讨论: 从变量的特点上分,可以分为简单对象的安全问题和集合对象的安全问题。简单对象只要使用lock关键字就可以解决问题,这里主要讨论集合对象的安全问题。 集合对象一般我们使用较多的有键值对的集合,如:字典,哈希表等,一般都会有key ---value对。 这里举个最简单的例子:我们在很多地方可以看到操作webCache缓存的代码,如下; 1 public  MyObject Get(String key) 2 {3    MyObject o;4    if(CacheHelper[key]==null){5      o=从数据库或者其他数据源获取o对象;6      CacheHelper.Insert(key,o,..........7    }8    return o;9} 上面代码貌似比较好的解决了缓存问题,但是确存在着效率浪费的问题。(假设上面的缓存内容是某个论坛的帖子) 当你网站的同时访问量够大,够多的时候,而第5行的运行需要一些时间的时候,可能发生,应用程序刚启动的时候,对于同一个key,有上百个人会同时来运行到第3行,此时上百个人判断出key的结果是null,此时全部一起去运行第5行(事实上对于同一个key,我们要让它只运行一次第5行)。 这个过程就是个很浪费效率的过程。 此时有人可能会问:“那我们在加载数据的时候锁不就得了”,看下面代码就是加锁的代码  1 private   static   object  lockhelp = new   object ();  2  3 public  MyObject Get(String key)  4 { 5    MyObject o; 6    if(CacheHelper[key]==null){ 7      lock(lockhelp){ 8        if(CacheHelper[key]==null){ 9          o=从数据库或者其他数据源获取o对象;10          CacheHelper.Insert(key,o,.11        }12      }13    }14    return o;15} 此时确实是解决了一个对象只被加载一次,不过确发生了更糟糕的问题。 服务器刚启动的时候,当n个人来运行的时候,无论来的是哪个key,都会导致阻赛等待,如果同时有3000人来访问,保证你的服务器挂机。 那么我们怎么解决这个问题呢。 我们可以..... 待续.....待续 还没写完呢,就看到赵兄在评论了。不错,赵兄的方法正解。要解决问题的方法还是比较简单的,主要问题是很多兄弟一下次眼昏没有注意到这个问题。 不过从完整的解决上来说,应该是新建一个字典,字典中key就是我们外面的key,字典中的value是我们的lockhelp,在读取之初,new一个lockhelp到字典中,然后加锁开始读取数据,而当字典中有这个key的lockhelp时,直接拿出来lock住。========================================================================== 这种方法:赵兄在3楼有所点评,赵兄的意思是如果同时操作的key过多,会产生大批量的锁。这确实是个问题。 如果我们要做如上方式缓存,一般情况下是对所有传进来的Key的相同率较高才会使用。如果key传进来基本上不一样,那么用上面这种缓存策略意义不是很大。如:论坛帖子,再热门的论坛我看也就最新的几篇,最热门的几篇,最精华的几篇的id传进来概率大。所以说,上面的缓存策略应用环境是针对key相同匹配率较高的环境,此时lockhelp不会出现超大的情况,毕竟我提出的问题是发生在 应用程序刚刚启动的时候,如果进入正常运行了是不会有这个问题的。 而针对key情况超大的时候,我们不是很必要用上面的缓存方法。key超大,说明缓存内容的差异性超大,每个人来访问的内容都会不一样。 ========================================================================== 对于6楼提出的问题,我想可以用简单的代码示范一下 代码一: 1 private   static  Object o = new  Object(); 2 3 public   void  MyF() {4     lock(o){5       //dosamething6     }7} 代码二: 1 public   void  MyF() {2     Object o=new Object();3     lock(o){4       //dosamething5     }6} 上面两个代码,代码一 就是n个人进来会阻塞,你认为代码二 n个人进来也会阻塞吗?你可以代码调式一下。 =========================================================================== 随着我们应用的越来越复杂,很多不同的情况下对线程安全都要做不同的处理。 如:当我们碰到对集合的更新是整个集合更新,而不是一个key一个key更新,更新频率又比较高,每次都是整个集合更新,这个时候我们又该如何保证我们的线程安全。 此时我们一般是采用在轮询过程中,先从数据库中提取新的集合到临时集合中,然后赋值给使用中的集合。

转载于:https://www.cnblogs.com/pooeo/archive/2008/01/25/1053864.html

相关资源:JAVA上百实例源码以及开源项目
最新回复(0)