我打算在多个线程之间共享一个List。该列表将在更改期间锁定,这种更改很少发生。如果同时通过列表从不同的线程进行多次迭代,是否存在线程安全问题?
答案 0 :(得分:11)
如果可以(如果可以使用.NET 4),请使用BlockingCollection<T>
:
为实现
IProducerConsumerCollection<T>
的线程安全集合提供阻止和绑定功能。
如果没有,则完全封装列表并添加访问List<T>'s
状态的线程安全方法。不要将列表的引用设置为public或从任何方法返回它 - 始终封装引用,以便您可以保证锁定对它的所有访问。
答案 1 :(得分:6)
List<T>
不是线程安全的类,但如果每次读/写时都锁定,则不会出现任何问题。根据文件:
公共静态(在Visual Basic中共享) 这种类型的成员是线程安全的。 任何实例成员都不是 保证是线程安全的。
List<T>
可以支持多个读者 同时,只要 集合未被修改。 列举一个集合是 本质上不是线程安全的 程序。在罕见的情况下 枚举与一个或多个竞争 写访问,唯一的方法来确保 线程安全是锁定 整个收集 列举。允许收集 由多个线程访问 读书和写作,你必须 实现自己的同步。
答案 2 :(得分:4)
List<T>
通常不是线程安全的。拥有多个阅读器不会导致任何问题,但是,在阅读时您无法写入列表。因此,您需要锁定读取和写入,或者使用类似System.Threading.ReaderWriterLock
(允许多个读者但只允许一个编写者)的内容。
答案 3 :(得分:1)
如果那就是你要问的话,它可以同时从多个线程读取。如果是这样,请考虑读写器锁。
答案 4 :(得分:0)
要回答这个问题,您必须先查看文档,然后查看源代码,这里有一个警告 - List<T>
的源代码可以是经过多年的修改。
Darin Dimitrov 引用了 2010 年的文档,与 2021 年有所不同:
<块引用>这种类型的公共静态(在 Visual Basic 中共享)成员是线程 安全的。不保证任何实例成员都是线程安全的。
对一个 List 执行多次读取操作是安全的,但是 如果在读取集合时修改集合,则可能会出现问题。 为确保线程安全,在读取或写入期间锁定集合 手术。使集合可以被多个线程访问 对于读取和写入,您必须实现自己的同步。 对于具有内置同步的集合,请参阅 System.Collections.Concurrent 命名空间。对于本质上线程安全的 替代方法,请参阅 ImmutableList 类。
如你所见,已经没有这样的句子
<块引用>枚举集合本质上不是线程安全的 程序
所以建议是 - 检查 List<T>
的 documentation 和 implementation 并跟踪 .NET 框架上的更改。
您的问题的答案是 - 这取决于。
如果你使用foreach
来遍历列表,那么如果列表被修改了,即使只是调用list[i]=value
,其中value
等于list[i]
,你将成为异常,因为 List<T>._version
(将由枚举器对象检查)在设置时更改。
for
这个地方的循环不会抛出异常,如果你要修改列表中的一个值,但是改变列表的长度是很危险的。
如果列表在迭代过程中根本不会被修改,那么迭代是线程安全的。