我可以在没有锁定的情况下从多个线程安全地调用List.AddRange(r)吗?如果没有,我会遇到什么样的麻烦?
答案 0 :(得分:17)
否,its documentation并未表示它是线程安全的,因此不是。
公共静态(在Visual Basic中共享) 这种类型的成员是线程安全的。 任何实例成员都不是 保证是线程安全的。
关于可能出现的问题,请考虑AddRange(newItems)的作用:
现在想想如果上面的内容与另一个AddRange()调用混合在一起甚至只是调用一个项目,会发生什么。
答案 1 :(得分:6)
不,不是,但是我想在锁内做myList.AddRange(...);
比做几个lock (syncLock) { myList.Add(...) };
更有效率。
你会遇到哪种麻烦?当一个线程正在添加一个项目而另一个线程正在枚举列表时,List<T>
将抛出某个异常,因为它会进行一些内部版本控制,因为它希望阻止我们的开发人员遇到令人讨厌的副作用。
此外List<T>
内部保留一个数组,用于存储其项目。也许在数组中设置一个项目是非常原子的,但是每当达到此数组的容量时,将创建一个新项目,并且将从旧项目中复制项目。因此,当一个线程想要在复制过程中添加一些东西时,你可以想象事情会不同步。
答案 2 :(得分:3)
在.NET Framework 4.0之前,没有.NET集合是线程安全的。在您使用代码 Collections and Synchronization (Thread Safety)
访问它之前,您需要锁定它。
另一方面,.NET Framework 4.0引入了新的System.Collections.Concurrent
命名空间,其中包含细粒度的Thread-Safe Collections
。
最后,如果您可以使用.NET Framework 4.0,我强烈建议您根据需要执行此操作,否则,请确保每次要修改或访问它时都锁定该集合。
此外,静态集合应该是线程安全的,但要注意,因为不保证成员。
编辑#1
根据Steve Townsend的评论进一步验证后,我承认.NET Framework中有三个线程安全的集合,从3.0版本开始:
答案 3 :(得分:3)
根据您的使用情况,SynchronizedCollection可能有效。
但你没有单发AddRange
。如果您只是使用它来为集合设定种子,则可以执行此操作,因为IEnumerable
构造函数已超载。
答案 4 :(得分:1)
不,它不是线程安全的。
线程A可以在列表中调用AddRange。它可以部分迭代集合并切换线程。
线程B可以在线程A完成之前调用添加/删除等。