zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    最棒的HyperV监控工具 HyperV Gadget
    VSTS 强制TFS更新用户组权限
    Touch Diamond 印象
    Travelers
    Touch 全能名片王
    惠普前总裁孙振耀指点职业规划
    Shinning 我所听过最棒的演讲
    DB2 9 运用开辟(733 考试)认证指南,第 2 局部: DB2 数据独霸(9)
    DB2 9 使用斥地(733 测验)认证指南,第 1 局部: 数据库对象与编程措施(2)
    DB2 9 行使启示(733 检验)认证指南,第 2 部分: DB2 数据行使(2)
  • 原文地址:https://www.cnblogs.com/hirisw/p/9378895.html
Copyright © 2011-2022 走看看