在之前一段时间里面,我的基类多数使用lock和Hashtable组合实现多线程内缓存的冲突处理,不过有时候使用这两个搭配并不尽如人意,偶尔还是出现了集合已经加入的异常,对代码做多方的处理后依然如故,最后采用了.NET 4.0后才引入的ConcurrentDictionary多线程同步字典集合,问题顺利解决。

1、使用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 = ; i < ; i++)
{
Thread thread = new Thread(() =>
{
var result = BLLFactory<Customer>.Instance.FindFirst();
Console.WriteLine(result.ToJson());
Console.WriteLine();
}); list.Add(thread);
} for (int i = ; i < list.Count; i++)
{
list[i].Start();
}
}
catch(Exception ex)
{
LogTextHelper.Error(ex);
}

跟踪代码得到错误信息如下所示。

因此,从上面代码可以看到,使用lock(syncRoot)也无法出现的多线程冲突问题。

2、使用ConcurrentDictionary替代Hashtable

ConcurrentDictionary是.net4.0推出的一套线程安全集合里的其中一个,和它一起被发行的还有ConcurrentStack,ConcurrentQueue等类型,它们的单线程版本(线程不安全的,Queue,Stack,Dictionary)我们一定不会陌生。ConcurrentDictionary<TKey, TValue> 可由多个线程同时访问,且线程安全,用法同Dictionary很多相同,但是多了一些方法。ConcurrentDictionary 属于System.Collections.Concurrent 命名空间。

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对多线程的对象缓存处理,能够顺利解决问题的时候,发现其访问效率也是较之前有所提高,一举两得。

使用ConcurrentDictionary替代Hashtable对多线程的对象缓存处理的更多相关文章

  1. ConcurrentHashMap能完全替代HashTable吗?

    至此你应该能够明白,ConcurrentHashMap与HashTable都可以用于多线程的环境,但是当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间.因为C ...

  2. Java多线程基础——对象及变量并发访问

    在开发多线程程序时,如果每个多线程处理的事情都不一样,每个线程都互不相关,这样开发的过程就非常轻松.但是很多时候,多线程程序是需要同时访问同一个对象,或者变量的.这样,一个对象同时被多个线程访问,会出 ...

  3. 多线程 同步对象 event 简单实例 &进程间通信

    多线程 同步对象event import threading,time class Boss(threading.Thread): def run(self): print("BOSS:今晚 ...

  4. 分布式内存对象缓存系统Memcached-概述

    全面掌握Memcached 1.       概述 Memcached是danga.com(运营LiveJournal的技术团队)开发的一套分布式内存对象缓存系统,是为了加快网站http://www. ...

  5. spring ehcache 页面、对象缓存

    一.Ehcache基本用法 CacheManager cacheManager = CacheManager.create(); // 或者 cacheManager = CacheManager.g ...

  6. Ehcache 整合Spring 使用页面、对象缓存

    Ehcache 整合Spring 使用页面.对象缓存 Ehcache在很多项目中都出现过,用法也比较简单.一 般的加些配置就可以了,而且Ehcache可以对页面.对象.数据进行缓存,同时支持集群/分布 ...

  7. (转)Ehcache 整合Spring 使用页面、对象缓存

    Ehcache在很多项目中都出现过,用法也比较简单.一般的加些配置就可以了,而且Ehcache可以对页面.对象.数据进行缓存,同时支持集群/分布式缓存.如果整合Spring.Hibernate也非常的 ...

  8. 缓存插件 EHCache 对象缓存(Spring)

    对象缓存就是将查询的数据,添加到缓存中,下次再次查询的时候直接从缓存中获取,而不去数据库中查询. 对象缓存一般是针对方法.类而来的,结合Spring的Aop对象.方法缓存就很简单.这里需要用到切面编程 ...

  9. 高性能的分布式内存对象缓存系统Memcached

    Memcached概述   什么是Memcached? 先看看下面几个概念: Memory:内存存储,不言而喻,速度快,对于内存的要求高,不指出的话所缓存的内容非持久化.对于CPU要求很低,所以常常采 ...

随机推荐

  1. 跟着刚哥梳理java知识点——异常(十一)

    异常:将程序执行中发生的不正常情况(当执行一个程序时,如果出现异常,那么异常之后的代码就不在执行.) java.lang.Throwable:异常的超类 1.Error:java虚拟机无法解决的严重问 ...

  2. java多线程基本概述(五)——线程通信

    线程之间的通信可以通过共享内存变量的方式进行相互通信,也可以使用api提供的wait(),notify()实现线程之间的通信.wait()方法是Object类的方法,改方法用来将当前的线程置入&quo ...

  3. Spring+SpringMVC+MyBatis+easyUI整合优化篇(十一)数据层优化-druid监控及慢sql记录

    本文提要 前文也提到过druid不仅仅是一个连接池技术,因此在将整合druid到项目中后,这一篇文章将去介绍druid的其他特性和功能,作为一个辅助工具帮助提升项目的性能,本文的重点就是两个字:监控. ...

  4. angular 自定义filter

    用modul.filter .filter("fiilterCity",function(){ return function(obj){ var newObj = []; ang ...

  5. Linux - 进程调度算法

    进程调度: 无论是在批处理系统还是分时系统中,用户进程数一般都多于处理机数.这将导致它们互相争夺处理机.另外,系统进程也同样需要使用处理机. 这就要求进程调度程序按一定的策略,动态地把处理机分配给处于 ...

  6. 【Spark2.0源码学习】-3.Endpoint模型介绍

         Spark作为分布式计算框架,多个节点的设计与相互通信模式是其重要的组成部分.   一.组件概览      对源码分析,对于设计思路理解如下:            RpcEndpoint: ...

  7. 原生js实现数据双向绑定

    最近接触了vue,在谈到vue等等的mvvm框架之前,先了解什么是数据双向绑定以及如何利用原生JS实现数据双向绑定 单向数据绑定 指先把模板写好,然后把模板和数据(数据可能来自后台)整合到一起形成HT ...

  8. js 数字递增特效 仿支付宝我的财富 HTML5

    上周五应着公司临时需求,一天的时间解决掉官网(ps:比较简单哈哈),需求里面有一个特效就是数字递增到指定的数值,其实JS写也不复杂的,但是我发现一个js小插件,这个插件轻巧简单,用起来也非常简单实用. ...

  9. Python基本语法--语句

    # -*- coding: utf-8 -*- #条件语句 ''' if 判断条件: 执行语句…… else: 执行语句…… ''' flag = False name = 'python' if n ...

  10. 工具类总结---(四)---Sharedpreferences保存

    用于保存具有对应关系的键值对 import android.content.Context; import android.content.SharedPreferences; import java ...