List是线程安全的吗?如果不是该怎么办呢?安全的List对性能的影响有多大呢?
测试条件:
开启2个并行执行任务,往同一个list对象写入值
测试代码:
static int maxNum = ;
static List<int> list = new List<int>();
static void Main(string[] args)
{
//迭代次数
int iterationNum = ;
CodeTimer.Initialize();
CodeTimer.Time("List是否是线程安全的呢?", iterationNum, new Action(ListIsThreadSafe));
//Console.Write(sbIsThreadSafe.ToString());
Console.Read();
}
private static void ListIsThreadSafe()
{
Parallel.For(, maxNum / , (i) =>
{
list.Add(i);
});
Parallel.For(maxNum / + , maxNum, (i) =>
{
list.Add(i);
});
}
测试结果:

测试结论:
之所以会造成以上的结果是因为list对象不是线程安全。那该怎么办呢?
这时我们需要使用System.Collections.Concurrent命名空间下的类型来用于并行循环体内。
|
类 |
说明 |
|
BlockingCollection<T> |
为实现 IProducerConsumerCollection<T> 的线程安全 集合提供阻止和限制功能。 |
|
ConcurrentBag<T> |
表示对象的线程安全的无序集合。 |
|
ConcurrentDictionary<TKey, TValue> |
表示可由多个线程同时访问的键值对的线程安全集合。 |
|
ConcurrentQueue<T> |
表示线程安全的先进先出 (FIFO) 集合。 |
|
ConcurrentStack<T> |
表示线程安全的后进先出 (LIFO) 集合。 |
|
OrderablePartitioner<TSource> |
表示将一个可排序数据源拆分成多个分区的特定方式。 |
|
Partitioner |
提供针对数组、列表和可枚举项的常见分区策略。 |
|
Partitioner<TSource> |
表示将一个数据源拆分成多个分区的特定方式。 |
我们再来进行一次测试。
测试代码:
static int maxNum = ;
static ConcurrentQueue<int> safeList = new ConcurrentQueue<int>();
static void Main(string[] args)
{
//迭代次数
int iterationNum = ;
CodeTimer.Initialize();
CodeTimer.Time("ConcurrentQueue是否是线程安全的呢?", iterationNum, new Action(ListIsThreadSafe));
//Console.Write(sbIsThreadSafe.ToString());
Console.Read();
}
private static void ListIsThreadSafe()
{
Parallel.For(, maxNum / , (i) =>
{
safeList.Enqueue(i);
});
Parallel.For(maxNum / + , maxNum, (i) =>
{
safeList.Enqueue(i);
});
}
测试结果:

测试结论:
ConcurrentQueue是线程安全的。在遇到多线程和并行开发时应该使用ConcurrentQueue而不是List.
疑问:为了确保对象线程安全,系统底层实现机制必定是要使用对象加锁和解锁的功能来确保对象安全,那么加锁和解锁是否会对性能造成影响呢?
我们再来进行一组测试:
测试条件:
(1)对100万个数据进行普通的循环运算然后添加到List集合对象中。
(2)对100万个数据进行并行循环运算然后添加到ConcurrentQueue集合对象中。
测试代码:
static int maxNum = ;
static List<BigInteger> list = new List<BigInteger>();
static ConcurrentQueue<BigInteger> safeList = new ConcurrentQueue<BigInteger>();
static void Main(string[] args)
{
//迭代次数
int iterationNum = ;
CodeTimer.Initialize();
CodeTimer.Time("普通的循环运算", iterationNum, new Action(NormalCompute));
CodeTimer.Time("并行循环运算_1", iterationNum, new Action(ParallelCompute_1));
CodeTimer.Time("并行循环运算_2", iterationNum, new Action(ParallelCompute_2));
Console.Read();
}
private static void NormalCompute()
{
for (int i = ; i <= maxNum; i++)
{
Math.Pow(i, i + );
list.Add(new BigInteger(i));
}
}
private static void ParallelCompute_1()
{
Parallel.For(, maxNum, (i) =>
{
Math.Pow(i, i + );
safeList.Enqueue(new BigInteger(i));
});
}
private static void ParallelCompute_2()
{
Parallel.For(, maxNum / , (i) =>
{
Math.Pow(i, i + );
safeList.Enqueue(new BigInteger(i));
});
Parallel.For(maxNum / + , maxNum, (i) =>
{
Math.Pow(i, i + );
safeList.Enqueue(new BigInteger(i));
});
}
测试结果:

测试结论:
和我预期的结论是一样的,并行方式所耗费的时间更加的长。线程安全的加锁和解锁对性能的影响还是比较大的。
List是线程安全的吗?如果不是该怎么办呢?安全的List对性能的影响有多大呢?的更多相关文章
- Java线程并发中常见的锁
随着互联网的蓬勃发展,越来越多的互联网企业面临着用户量膨胀而带来的并发安全问题.本文着重介绍了在java并发中常见的几种锁机制. 1.偏向锁 偏向锁是JDK1.6提出来的一种锁优化的机制.其核心的思想 ...
- Java线程并发中常见的锁--自旋锁 偏向锁
随着互联网的蓬勃发展,越来越多的互联网企业面临着用户量膨胀而带来的并发安全问题.本文着重介绍了在java并发中常见的几种锁机制. 1.偏向锁 偏向锁是JDK1.6提出来的一种锁优化的机制.其核心的思想 ...
- NHibernate中Session的处理 线程不安全
NHibernate中Session是线程不安全的,而且每次数据库操作 请求创建Session时对性能有些影响.在Windows应用中可以通过 [ThreadStatic]特性很简单的就可以实现线程安 ...
- C#异步编程(三)内核模式线程同步
其实,在开发过程中,无论是用户模式的同步构造还是内核模式,都应该尽量避免.因为线程同步都会造成阻塞,这就影响了我们的并发量,也影响整个应用的效率.不过有些情况,我们不得不进行线程同步. 内核模式 wi ...
- iOS 25个性能优化/内存优化常用方法
1. 用ARC管理内存 ARC(Automatic ReferenceCounting, 自动引用计数)和iOS5一起发布,它避免了最常见的也就是经常是由于我们忘记释放内存所造成的内存泄露.它自动为你 ...
- MST 001
一.String,StringBuffer, StringBuilder 的区别是什么?String为什么是不可变的? 答: 1.String是字符串常量,StringBuffer和StringB ...
- (转)MySQL配置文件mysql.ini参数详解、MySQL性能优化
本文转自:http://www.cr173.com/html/18331_1.html my.ini(Linux系统下是my.cnf),当mysql服务器启动时它会读取这个文件,设置相关的运行环境参数 ...
- 知方可补不足~sqlserver中的几把锁~续
回到目录 之前写过相关的文章,对脏读,不可重复读,幻读都做了相当的研究,而今天在程序中又出现了这个问题,即当一条数据被update时,另一个线程同时发起了读的操作,这对于序列化级别的事务是不被允许的, ...
- iOS-------应用性能调优的25个建议和技巧
性能对 iOS 应用的开发尤其重要,如果你的应用失去反应或者很慢,失望的用户会把他们的失望写满App Store的评论.然而由于iOS设备的限制,有时搞好性能是一件难事.开发过程中你会有很多需要注意的 ...
随机推荐
- IOS开发笔记(4)数据离线缓存与读取
IOS开发笔记(4)数据离线缓存与读取 分类: IOS学习2012-12-06 16:30 7082人阅读 评论(0) 收藏 举报 iosiOSIOS 方法一:一般将服务器第一次返回的数据保存在沙盒里 ...
- iOS中3种正则表达式的使用与比较-备
1.利用NSPredicate(谓词)匹配 例如匹配有效邮箱: ? 1 2 3 4 NSString *email = @“nijino_saki@163.com”: NSString *regex ...
- Windows软件使用Q&A集锦【持续更新】
以下不注明原创的均为转载,感谢原作者,希望大家电脑用的都舒心 Q: QQ电脑管家的默认程序的程序推荐如何关闭?我右键点击文件打开方式,选择默认程序的时候,qq管家总弹出来,还给我推荐程序.如何关闭? ...
- tessnet2 在vs2010 及以上版本不能调用的解决方案
<startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version=&qu ...
- 捆绑和缩小(BundleConfig.RegisterBundles) 第五章 : MVC中的使用 | {version}用法
使用捆绑与 ASP.NET MVC 放缩法 在这一节我们将创建 ASP.NET MVC 项目,审查捆绑和缩小.首先,创建一个新的 ASP.NET MVC 互联网项目,命名为MvcBM ,而无需更改任何 ...
- 期望dp-hdu-4336-Card Collector
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4336 题目大意: 有n种卡片,每包中至多有一种卡片,概率分别为p1,p2,...pn,可能有的没有卡 ...
- 初步swift语言学习笔记9(OC与Swift杂)
笔者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/34440159 转载请注明出处 假设认为文章对你有所帮助,请通过留言 ...
- Oracle中drop user和drop user cascade的区别
drop user : 仅仅是删除用户,drop user username cascade :会删除此用户名下的所有表和视图. userSpecify the user to be dropped. ...
- PHP session 跨子域问题总结
Session主要分两部分: 一个是Session数据,该数据默认情况下是存放在服务器的tmp文件下的,是以文件形式存在 另一个是标志着Session数据的Session Id,Session ID, ...
- 如何在程序退出的时候清除activity栈
在公司里接手了一个后期的项目,由于项目前期对activity栈管理的不够谨慎,所以导致了在某些情况下程序退出的时候没有将activity栈清除掉.在网上找到的无非就是那几种例子,都不是最好的解决办法. ...