C#多线程List的非线程安全性
背景:最近在做多线程方面的工作,工作中发现多线程中很多坑,这里就有一个List添加对象的误区,这里做个分享跟大家讲讲这个坑是怎么形成的怎么样避免。
示例:
代码及错误:

如果单单只从程序逻辑上看,应该没有逻辑错误,但是结果却是是有为空值的情况,这时候有些多线程经验的读者可能会想到,构造函数也是一个函数,有可能在往List中添加对象的时候,构造函数还没有将对象返回就执行了添加操作,造成了这个问题的出现,下面我们来验证一下这个观点是否正确。

从图中可以看到,在对象new之后立即执行了取属性操作,如果构造函数没有返回立即执行后面肯定会出现空指针异常,但是这里并没有出问题,说明不是构造函数返回结果的问题,同时也说明了构造函数是具有线程安全的。
为此可以怀疑这个问题是优于List.Add方法造成的,为此,查看一下List.Add方法的源码可以了解其中的原委。

点开this.EnsureCapacity(this.size+1);方法,如下图所示:

这时候,我们就可以猜测到问题就出现在这个容量扩展方法这里了,于是我尝试着修改List的最初容量,使之不需要进行容量扩展,此时程序运行正常,说明问题的确就在这里。

虽然说问题解决了,问题的原因也知道了,但是为什么会有这样的问题呢?内存扩容是如何形成这个错误的呢,于是和六爷讨论了一下这个问题,很感谢六爷指点迷津,让我知道了这其中的具体原因,我画个简图给大家讲解一下,希望大家能看明白:

验证:
假设真的是这个原因造成的应该出现空值的位置应该都是2的整数次幂之后的值,并且如果内存越大拷贝的时间越长,出现空值的几率就越大,于是改造程序,可以验证六爷的这个猜测:
代码:

结果,8192=4096*2,16384=8192*2:

解决方案:
1.扩容List的初始容量为集合需要的实际容量或更大
2.给List.Add方法加锁
3.使用List的线程安全版本,如下图所示:

源代码:
https://download.csdn.net/download/hirisw/10769789
C#多线程List的非线程安全性的更多相关文章
- Java 多线程:什么是线程安全性
线程安全性 什么是线程安全性 <Java Concurrency In Practice>一书的作者 Brian Goetz 是这样描述"线程安全"的:"当多 ...
- Linux c readdir是非线程安全,需用readdir_r,要注意用静态变量当做返回值的函数的非线程安全性
readdir函数: struct dirent *readdir(DIR *dirp); The data returned by readdir() may be overwritten by ...
- JAVA中的线程安全与非线程安全
原文:http://blog.csdn.net/xiao__gui/article/details/8934832 ArrayList和Vector有什么区别?HashMap和HashTable有什么 ...
- Java 非线程安全的HashMap如何在多线程中使用
Java 非线程安全的HashMap如何在多线程中使用 HashMap 是非线程安全的.在多线程条件下,容易导致死循环,具体表现为CPU使用率100%.因此多线程环境下保证 HashMap 的线程安全 ...
- Java多线程编程(3)--线程安全性
一.线程安全性 一般而言,如果一个类在单线程环境下能够运作正常,并且在多线程环境下,在其使用方不必为其做任何改变的情况下也能运作正常,那么我们就称其是线程安全的.反之,如果一个类在单线程环境下运作 ...
- Java多线程之非线程安全
在Java多线程中我会重点总结五个如下的技术点: 1.非线程安全是如何出现的 2.synchronized对象监视器为Objec时的使用 3.synchronized对象监视器为Class时的使用 4 ...
- 【多线程补充】SimpleDateFormat非线程安全与线程中、线程组中异常的处理
1.SimpleDateFormat非线程安全的问题 类SimpleDateFormat主要负责日期的转换与格式化,但在多线程环境中,使用此类容易造成数据转换及处理的不正确,因为SimpleDateF ...
- java 多线程 线程安全及非线程安全的集合对象
一.概念: 线程安全:就是当多线程访问时,采用了加锁的机制:即当一个线程访问该类的某个数据时,会对这个数据进行保护,其他线程不能对其访问,直到该线程读取完之后,其他线程才可以使用.防止出现数据不一致或 ...
- 刨根问底系列(3)——关于socket api的原子操作性和线程安全性的探究和实验测试(多线程同时send,write)
多个线程对同一socket同时进行send操作的结果 1. 概览 1.1 起因 自己写的项目里,为了保证连接不中断,我起一个线程专门发送心跳包保持连接,那这个线程在send发送数据时,可能会与主线程中 ...
随机推荐
- python爬虫scrapy框架——爬取伯乐在线网站文章
一.前言 1. scrapy依赖包: 二.创建工程 1. 创建scrapy工程: scrapy staratproject ArticleSpider 2. 开始(创建)新的爬虫: cd Artic ...
- CMD下利用subst命令将一个文件夹镜像成本地的一个虚拟磁盘
我们都知道net use可以建立网络驱动器映射,这里不说了. 我今天刚看到这命令的,叫镜像虚拟磁盘subst命令,这个命令可以简化好多操作,比如一个常用的文件放在一个路径很深的文件夹中,每次我们想要操 ...
- Ajax基础(五)--封装库
jQuery ajax请求的基本语法: 一.封装为对象: ajax.txt代码: {"id":"102","username":" ...
- visual stdio 2012 c#学习笔记1
visual stdio 2012 c#学习笔记1 1 我在安装过程中选择的是英文版本,不过刚入手,所以想先从中文菜单入手,所以需要安装中文语言包: microsoft的中文语言包下载地址为:http ...
- JsonTools 工具类
import net.sf.json.JSONObject; public class JsonTools { public static JSONObject getJSONObject(Strin ...
- linux应用之wget命令详解
wget是linux最常用的下载命令, 一般的使用方法是: wget + 空格 + 要下载文件的url路径 例如: # wget linuxsense.org/xxxx/xxx.tar.gz" ...
- Oracle11g数据库监听配置
(转自:http://blog.sina.com.cn/s/blog_6908928501018057.html) 经验告诉我:最好把数据库的SID和数据库全局名称分开,免得配置时混了,如果要配置服务 ...
- Sqlite/ FMDB
Sqlite 1. Sqlite数据库 > 数据库? 按数据结构来组织,存储和管理数据的仓库. > 关系型数据库:使用二维表及其之间的联系组织成一个数据组织. 关系:可以理解为一张二维表, ...
- react pagination
class AppPagination extends React.Component { handleChange(pageNum) { this.props.handleChangePage(pa ...
- pgbench使用记录
1.初始化: pgbench -i pgbench 如果端口号有变化,需要先手动创建数据库,再执行. pgbench -i -s 10 -p 5433 pgbench 重点:主要用到两个参数,-i:初 ...