[英]Loop count != list.Count - Populating List<string> in new threads
为什么以下代码的结果(list.Count)总是大约是18100而不是预期的19000?
var list = new List<string>(19000);
List<Task> tl = new List<Task>(19000);
for (int q = 0; q < 19000; q++)
{
tl.Add(Task.Factory.StartNew(() =>
{
var k = "something";
list.Add(k);
}));
}
Task.WaitAll(tl.ToArray());
Console.WriteLine(list.Count);
问题是List<T>
不是线程安全的。
您可以在System.Collections.Concurrent
使用线程安全的集合,并使用ConcurrentBag<>
类型。 试试这个:
var list = new ConcurrentBag<string>();
List<Task> tl = new List<Task>(19000);
for (int q = 0; q < 19000; q++)
{
tl.Add(Task.Factory.StartNew(() =>
{
var k = "something";
list.Add(k);
}));
}
Task.WaitAll(tl.ToArray());
Console.WriteLine(list.Count);
还有其他线程安全类型,如ConcurrentQueue<>
, ConcurrentStack<>
等。
另一方面,您可以使用lock
keyworkd来阻止其他线程访问同一个语句块。 在这种情况下,您可以使用List<T>
和非线程安全对象作为示例:
该对象必须对所有线程都可见,因此,您可以在类范围内声明它,对于示例:
private static object _sync = new object();
在它之后,尝试在需要修改时锁定此实例,对于示例:
var list = new List<string>(19000);
List<Task> tl = new List<Task>(19000);
for (int q = 0; q < 19000; q++)
{
tl.Add(Task.Factory.StartNew(() =>
{
lock(_sync)
{
var k = "something";
list.Add(k);
}
}));
}
Task.WaitAll(tl.ToArray());
Console.WriteLine(list.Count);
List<T>
类不是线程安全的,请参阅MSDN
此类型的公共静态(在Visual Basic中为Shared)成员是线程安全的。 任何实例成员都不保证是线程安全的。
在List上执行多个读取操作是安全的,但如果在读取集合时修改了集合,则可能会出现问题。 要确保线程安全,请在读取或写入操作期间锁定集合。 要使多个线程可以访问集合以进行读写,您必须实现自己的同步。 对于具有内置同步的集合,请参阅System.Collections.Concurrent命名空间中的类。 有关本质上线程安全的替代方法,请参阅ImmutableList类。
List(T)
不是线程安全的。
https://msdn.microsoft.com/en-us/library/6sh2ey19%28v=vs.110%29.aspx
此类型的公共静态成员是线程安全的。 任何实例成员都不保证是线程安全的。
因此,不能保证从多个线程分配给它可以产生所需的结果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.