使用ConcurrentDictionary替代Hashtable對多線程的對象緩存處理

在以前一段時間裏面,個人基類多數使用lock和Hashtable組合實現多線程內緩存的衝突處理,不過有時候使用這兩個搭配並不盡如人意,偶爾仍是出現了集合已經加入的異常,對代碼作多方的處理後依然如故,最後採用了.NET 4.0後才引入的ConcurrentDictionary多線程同步字典集合,問題順利解決。緩存

一、使用lock和Hashtable組合實現

在個人基類裏面,構建業務對象,通常用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替代Hashtable

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對多線程的對象緩存處理,可以順利解決問題的時候,發現其訪問效率也是較以前有所提升,一箭雙鵰。

相關文章
相關標籤/搜索