为什么以下代码的结果(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);
Run Code Online (Sandbox Code Playgroud)
问题是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);
Run Code Online (Sandbox Code Playgroud)
还有其他的线程安全的类型,如ConcurrentQueue<>,ConcurrentStack<>等.
另一方面,您可以使用lockkeyworkd来阻止其他线程访问同一个语句块.在这种情况下,您可以使用List<T>和非线程安全对象,用于示例:
该对象必须对所有线程都可见,因此,您可以在类范围内声明它,对于示例:
private static object _sync = new object();
Run Code Online (Sandbox Code Playgroud)
在它之后,尝试在需要修改时锁定此实例,对于示例:
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);
Run Code Online (Sandbox Code Playgroud)