obj.Coll 在您枚举时已更改。如果它没有被当前线程改变,它可能被其他线程改变。如果当前线程更改了集合,基本上有两种方法可以解决问题:可以创建集合的副本并枚举副本,也可以推迟更改直到枚举集合。
但是,如果集合被另一个线程更改,您应该以线程安全的方式访问该集合(不仅仅是这里,而是无处不在)。
编辑 基伦·约翰斯通:
我写了一个简短的代码来证明List<T>.ToArray() 不是线程安全的。
var list = new List<int>();
Task.Factory.StartNew(() => {
for (int i = 0; i < 1000000; ++i) {
list.Clear();
// Add values from 1 to 9
for (int j = 1; j < 10; ++j) {
list.Add(j);
}
}
Console.WriteLine("Thread Exit: list.Add()");
});
Task.Factory.StartNew(() => {
for (int i = 0; i < 100; ++i) {
var array = list.ToArray();
if (array.Length > 0) {
Console.WriteLine("ToArray(): {0}", string.Join(", ", array));
}
}
Console.WriteLine("Thread Exit: list.ToArray()");
});
下面是输出的sn-p。我想这证明了我的主张。 sn-p 包含 15 行,其中 9 行包含错误数据。
ToArray(): 1, 2, 3, 4
ToArray(): 1, 2, 3, 4, 5, 0, 0, 0, 0
ToArray(): 1, 2, 3, 4, 5, 6, 7, 0, 0
ToArray(): 0, 0, 0, 0, 0, 0, 0, 0, 0
ToArray(): 1, 2, 3, 4, 5, 0, 0, 0, 0
ToArray(): 0, 0, 0, 4, 5, 6, 7
ToArray(): 1, 2, 0, 0, 0, 0, 0, 0, 0
ToArray(): 1, 2, 3
ToArray(): 1, 0, 0, 0, 0, 0, 0, 0, 0
ToArray(): 0, 0, 0, 0, 0, 0, 0, 0
ToArray(): 1, 2
ToArray(): 1, 2, 3
ToArray(): 0, 0, 0, 0, 0, 0, 0, 0
ToArray(): 1, 2, 3, 4
ToArray(): 1, 2, 3, 4, 5, 6, 7, 8
如果我们使用list.Insert(0, j) 而不是list.Add(j),将会有更多变化。