转载:http://www.javashuo.com/article/p-pkwjnlso-gr.htmlhtml
在以前一段时间里面,个人基类多数使用lock和Hashtable组合实现多线程内缓存的冲突处理,不过有时候使用这两个搭配并不尽如人意,偶尔仍是出现了集合已经加入的异常,对代码作多方的处理后依然如故,最后采用了.NET 4.0后才引入的ConcurrentDictionary多线程同步字典集合,问题顺利解决。缓存
在个人基类里面,构建业务对象,通常用BLLFactory<T>.Instance就能够得到对应业务对象的应用了。安全
var result = BLLFactory<Customer>.Instance.FindFirst(); Console.WriteLine(result.ToJson());
所以使用BLLFactory<T>.Instance这个构建对象后,把它们放到HashTable里面,因为须要设计多线程冲突处理,所以须要使用lock对象来实现锁定的处理。多线程
HashTable表示键/值对的集合。在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现相似key-value的键值对,其中key一般可用来快速查找,同时key是区分大小写;value用于存储对应于key的值。Hashtable中key-value键值对均为object类型,因此Hashtable能够支持任何类型的keyvalue键值对,任何非 null 对象均可以用做键或值。并发
使用这种方式,偶尔在Web端,仍是出现多线程访问冲突的问题,为此咱们也能够使用多线程的测试代码来进行测试重现错误,测试
try { List<Thread> list = new List<Thread>(); for (int i = 0; i < 10; i++) { Thread thread = new Thread(() => { var result = BLLFactory<Customer>.Instance.FindFirst(); Console.WriteLine(result.ToJson()); Console.WriteLine(); }); list.Add(thread); } for (int i = 0; i < list.Count; i++) { list[i].Start(); } } catch(Exception ex) { LogTextHelper.Error(ex); }
跟踪代码获得错误信息以下所示。this
所以,从上面代码能够看到,使用lock(syncRoot)也没法出现的多线程冲突问题。spa
ConcurrentDictionary是.net4.0推出的一套线程安全集合里的其中一个,和它一块儿被发行的还有ConcurrentStack,ConcurrentQueue等类型,它们的单线程版本(线程不安全的,Queue,Stack,Dictionary)咱们必定不会陌生。ConcurrentDictionary<TKey, TValue> 可由多个线程同时访问,且线程安全,用法同Dictionary不少相同,可是多了一些方法。ConcurrentDictionary 属于System.Collections.Concurrent 命名空间。.net
System.Collections.Concurrent 命名空间提供多个线程安全集合类。当有多个线程并发访问集合时,应使用这些类代替 System.Collections 和 System.Collections.Generic 命名空间中的对应类型。线程
ConcurrentDictionary这个类提供了下面几个方法,用于对集合的处理
public bool TryAdd(TKey key, TValue value) public bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue) public TValue this[TKey key] { get; set; } public TValue AddOrUpdate(TKey key, Func<TKey, TValue> addValueFactory, Func<TKey, TValue, TValue> updateValueFactory) public TValue AddOrUpdate(TKey key, TValue addValue, Func<TKey, TValue, TValue> updateValueFactory) public TValue GetOrAdd(TKey key, TValue value) public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
使用ConcurrentDictionary来替代Hashtable,咱们来看看BLLFactory的类的实现代码以下所示。
/// <summary> /// 对业务类进行构造的工厂类 /// </summary> /// <typeparam name="T">业务对象类型</typeparam> public class BLLFactory<T> where T : class { //采用ConcurrentDictionary线程安全的集合类来缓存,替代Hashtable private static ConcurrentDictionary<string, object> conCurrentCache = new ConcurrentDictionary<string, object>(); /// <summary> /// 建立或者从缓存中获取对应业务类的实例 /// </summary> public static T Instance { get { string CacheKey = typeof(T).FullName; return (T)conCurrentCache.GetOrAdd(CacheKey, s => { var bll = Reflect<T>.Create(typeof(T).FullName, typeof(T).Assembly.GetName().Name); //反射建立,并缓存 return bll; }); } } }
咱们能够看到代码简化了不少,并且使用前面的多线程测试代码,也顺利获取数据,不会出现异常了。
运行代码能够顺利实现,不会出现以前使用Hashtable出现的多线程访问异常了。
以上就是引入ConcurrentDictionary替代Hashtable对多线程的对象缓存处理,可以顺利解决问题的时候,发现其访问效率也是较以前有所提升,一箭双雕。