我可以在没有锁定的情况下,安全地从多个线程中调用List.AddRange(r)吗?如果不能,我会遇到什么问题?
我可以在没有锁定的情况下,安全地从多个线程中调用List.AddRange(r)吗?如果不能,我会遇到什么问题?
不,该类的文档没有说明它是线程安全的,因此它不是线程安全的。
该类型的公共静态成员(在 Visual Basic 中为 Shared)是线程安全的。 任何实例成员都不能保证是线程安全的。
至于可能出现什么问题,请考虑 AddRange(newItems) 所执行的操作:
现在想象一下,如果将上述操作与另一个 AddRange() 的调用或者甚至只是读取一项的调用混合在一起会发生什么。
不是的,但我想补充一点,使用锁内执行 myList.AddRange(...);
要比多次使用锁来添加元素 lock (syncLock) { myList.Add(...) };
更高效。
你会遇到什么问题?当一个线程正在添加一个项而另一个线程正在枚举 list 时,List<T>
会抛出一个特定的异常,因为它进行了一些内部版本控制,以防止我们这些可怜的开发人员遭遇麻烦的副作用。
此外,List<T>
内部保持一个数组,其中存储其项目。也许在数组中设置项目是相当原子的,但当达到该数组的容量时,将创建一个新数组,项目将从旧数组复制过来。因此,当一个线程想要添加东西时,如果拷贝正在进行,你可以想象事情会变得不同步。
Collections and Synchronization (Thread Safety)
。System.Collections.Concurrent
命名空间,其中包括细粒度的 Thread-Safe Collections
。非常抱歉,我也刚刚了解到它们的存在。=)
System.Collections.Generic
中有一些在这里起作用并且早于4.0版本。 - Steve TownsendSynchronizedCollection<T>
,但IList<T>
泛型集合并不是线程安全的。谢谢你告诉我这个信息! - Will MarcouillerAddRange
。如果您仅使用此方法来填充集合,则可以使用 IEnumerable
构造函数重载来完成。不,它不是线程安全的。
线程A可能会在您的列表上调用AddRange。它可能部分地遍历集合并切换线程。
线程B可能会在线程A完成之前调用Add/Remove等操作。