循环计数!= list.Count -填充列表在新的线程
本文关键字:string 线程 列表 填充 list Count 循环 | 更新日期: 2023-09-27 17:50:16
为什么下面代码的结果(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(object)
另一方面,您可以使用lock
关键字来阻止其他线程访问同一语句块。在这种情况下,您可以使用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
在List上执行多个读操作是安全的,但如果在读取集合时修改集合,则可能发生问题。为确保线程安全,请在读或写操作期间锁定集合。要使一个集合能够被多个线程访问以进行读写,您必须实现自己的同步。关于内置同步的集合,请参阅System.Collections.Concurrent命名空间中的类。有关固有线程安全的替代方法,请参阅immutableelist类。
标题>List(T)
不是线程安全的。
此类型的公共静态成员是线程安全的。任何实例成员不能保证是线程安全的。
从多个线程分配给它的结果不能保证产生期望的结果