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

在之前一段時(shí)間里面,我的基類多數(shù)使用lock和Hashtable組合實(shí)現(xiàn)多線程內(nèi)緩存的沖突處理,不過有時(shí)候使用這兩個(gè)搭配并不盡如人意,偶爾還是出現(xiàn)了集合已經(jīng)加入的異常,對(duì)代碼做多方的處理后依然如故,最后采用了.NET 4.0后才引入的ConcurrentDictionary多線程同步字典集合,問題順利解決。

1、使用lock和Hashtable組合實(shí)現(xiàn)

在我的基類里面,構(gòu)建業(yè)務(wù)對(duì)象,一般用BLLFactory<T>.Instance就可以獲得對(duì)應(yīng)業(yè)務(wù)對(duì)象的應(yīng)用了。

var result = BLLFactory<Customer>.Instance.FindFirst();
Console.WriteLine(result.ToJson());

因此使用BLLFactory<T>.Instance這個(gè)構(gòu)建對(duì)象后,把它們放到HashTable里面,由于需要設(shè)計(jì)多線程沖突處理,因此需要使用lock對(duì)象來實(shí)現(xiàn)鎖定的處理。

HashTable表示鍵/值對(duì)的集合。在.NET Framework中,Hashtable是System.Collections命名空間提供的一個(gè)容器,用于處理和表現(xiàn)類似key-value的鍵值對(duì),其中key通常可用來快速查找,同時(shí)key是區(qū)分大小寫;value用于存儲(chǔ)對(duì)應(yīng)于key的值。Hashtable中key-value鍵值對(duì)均為object類型,所以Hashtable可以支持任何類型的keyvalue鍵值對(duì),任何非 null 對(duì)象都可以用作鍵或值。

使用這種方式,偶爾在Web端,還是出現(xiàn)多線程訪問沖突的問題,為此我們也可以使用多線程的測(cè)試代碼來進(jìn)行測(cè)試重現(xiàn)錯(cuò)誤

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);
}

跟蹤代碼得到錯(cuò)誤信息如下所示。



因此,從上面代碼可以看到,使用lock(syncRoot)也無法出現(xiàn)的多線程沖突問題。

2、使用ConcurrentDictionary替代Hashtable

ConcurrentDictionary是.net4.0推出的一套線程安全集合里的其中一個(gè),和它一起被發(fā)行的還有ConcurrentStack,ConcurrentQueue等類型,它們的單線程版本(線程不安全的,Queue,Stack,Dictionary)我們一定不會(huì)陌生。ConcurrentDictionary<TKey, TValue> 可由多個(gè)線程同時(shí)訪問,且線程安全,用法同Dictionary很多相同,但是多了一些方法。ConcurrentDictionary 屬于System.Collections.Concurrent 命名空間。
System.Collections.Concurrent 命名空間提供多個(gè)線程安全集合類。當(dāng)有多個(gè)線程并發(fā)訪問集合時(shí),應(yīng)使用這些類代替 System.Collections 和 System.Collections.Generic 命名空間中的對(duì)應(yīng)類型。
ConcurrentDictionary這個(gè)類提供了下面幾個(gè)方法,用于對(duì)集合的處理

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的類的實(shí)現(xiàn)代碼如下所示。

/// <summary>
/// 對(duì)業(yè)務(wù)類進(jìn)行構(gòu)造的工廠類
/// </summary>
/// <typeparam name="T">業(yè)務(wù)對(duì)象類型</typeparam>
public class BLLFactory<T> where T : class
{
    //采用ConcurrentDictionary線程安全的集合類來緩存,替代Hashtable
    private static ConcurrentDictionary<string, object> conCurrentCache = new ConcurrentDictionary<string, object>(); 

    /// <summary>
    /// 創(chuàng)建或者從緩存中獲取對(duì)應(yīng)業(yè)務(wù)類的實(shí)例
    /// </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); //反射創(chuàng)建,并緩存
                return bll;
            });
        }
    }
} 

我們可以看到代碼簡(jiǎn)化了很多,而且使用前面的多線程測(cè)試代碼,也順利獲取數(shù)據(jù),不會(huì)出現(xiàn)異常了。



運(yùn)行代碼可以順利實(shí)現(xiàn),不會(huì)出現(xiàn)之前使用Hashtable出現(xiàn)的多線程訪問異常了。



以上就是引入ConcurrentDictionary替代Hashtable對(duì)多線程的對(duì)象緩存處理,能夠順利解決問題的時(shí)候,發(fā)現(xiàn)其訪問效率也是較之前有所提高,一舉兩得。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Java SE 基礎(chǔ): 封裝、繼承、多態(tài) 封裝: 概念:就是把對(duì)象的屬性和操作(或服務(wù))結(jié)合為一個(gè)獨(dú)立的整體,并盡...
    Jayden_Cao閱讀 2,234評(píng)論 0 8
  • 九種基本數(shù)據(jù)類型的大小,以及他們的封裝類。(1)九種基本數(shù)據(jù)類型和封裝類 (2)自動(dòng)裝箱和自動(dòng)拆箱 什么是自動(dòng)裝箱...
    關(guān)瑋琳linSir閱讀 2,049評(píng)論 0 47
  • 一:java概述:1,JDK:Java Development Kit,java的開發(fā)和運(yùn)行環(huán)境,java的開發(fā)工...
    ZaneInTheSun閱讀 2,800評(píng)論 0 11
  • Hashtable和Dictionary <K, V>類型 1):?jiǎn)尉€程程序中推薦使用Dictionary,有泛型...
    依東望閱讀 1,383評(píng)論 0 0
  • 本系列出于AWeiLoveAndroid的分享,在此感謝,再結(jié)合自身經(jīng)驗(yàn)查漏補(bǔ)缺,完善答案。以成系統(tǒng)。 Java基...
    濟(jì)公大將閱讀 1,610評(píng)論 1 6

友情鏈接更多精彩內(nèi)容