我对List<T>
集合的线程安全性有疑问。
这是我的测试类:
Test t = new Test();
t.a = 100;
t.b = 20;
t.c = 10;
然后让我们说上面的10个实例已经创建并添加到List中,如下所示。
List<Test> tCollection = new List<Test>();
tCollection.add(t);
稍后我在tCollection
中遍历测试对象。
foreach(Test t in tCollection)
{
// do calculation
}
将对象添加到List<Test>
并通过List<Test>
进行迭代是否是线程安全的?
答案 0 :(得分:3)
答案 1 :(得分:2)
默认的.net集合不线程安全 这意味着它们不包含处理多线程访问的其他代码,因为这样的代码会降低它们在单线程方案中的性能。
正如亚历山大加尔金在另一个答案中所说,微软提供了一些collections that are tailor-made for multi-threaded access。但是,您会注意到没有ConcurrentList<T>
与List完全相同。这是因为创建具有列表的所有属性的线程安全列表,例如随机访问,插入和删除和良好的性能几乎是不可能的。
在您的情况下,最接近的等价物是System.Collections.Concurrent.ConcurrentQueue<T>或ConcurrentStack<T>。
但是,在您的情况下可能会有一种更简单的方法:
对列表的只读访问始终是线程安全的。您可以根据需要迭代列表或访问随机元素,只要您不更改列表即可。
向列表中添加元素不是线程安全的。如果你在添加元素时迭代列表,这将是显而易见的,你会得到一个例外:&#34;在枚举器被实例化之后修改了集合&#34; 。
但即使从多个线程添加元素而不同时迭代列表也是不安全的。你不会得到这样一个明显的错误,相反它有时会起作用,有时也不行。
如果您只在程序启动后添加一次元素,那么您可以使用普通列表。在单个编写器线程中向列表添加元素时,请确保没有启动读取器线程。将所有元素添加到列表后,可以根据需要从多个线程迭代它。
对于更复杂的场景,通常最好切换到ConcurrentQueue或ConcurrentStack,而不是使用lock
实现自己的线程安全方法。