最近在做一些代碼整理工作,涉及到List 線程安全問題,查了一些資料。網上有些資料說List 增減成員(Add , Remove) 是安全的,但不保證成員屬性值訪問安全性,及禁止對 List 跨線程遍歷訪問, 如 foreach 遍歷。
可以想象,有些跨線程操作(Add , Remove)List 集合時, 恰好 另一個線程正在通過 foreach遍歷, 這時會拋出異常) 。 有改進方案用 for 替代 foreach ,這樣仍會報下標越界錯誤。
因此 , 跨線程遍歷list 不安全毋庸置疑。 對List 增減成員是否安全,需要驗證才知道。
如下代碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace testQueue
{
class Program
{
static List<int> list = new List<int>();
static ManualResetEvent[] manu;
static object LockList = new object();
static void Main(string[] args)
{
manu = new ManualResetEvent[2];
manu[0] = new ManualResetEvent(false);
manu[1] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback(Task1));
ThreadPool.QueueUserWorkItem(new WaitCallback(Task2));
//等待完成
ManualResetEvent.WaitAll(manu);
//統計結果:
Console.WriteLine("count:{0}", list.Count);
Console.ReadKey();
}
public static void Task1(object obj)
{
// lock (LockList)
// {
for (int i = 0; i < 5000000; i++)
{
list.Add(i);
}
// }
Console.WriteLine("Task1 complete!");
manu[0].Set();
}
public static void Task2(object obj)
{
// lock (LockList)
// {
for (int i = 0; i < 5000000; i++)
{
list.Add(i);
}
// }
Console.WriteLine("Task2 complete!");
manu[1].Set();
}
}
}
結果:

我們知道, List 集合大小是動態分配的,此處表明,分配List 大小,與對 List 操作 , 應保證在同一線程。 為了避免List 運行中分配大小,在初使化時,設置了List 大小:
static List<int> list = new List<int>(10000000);
再看看結果:

增加線程鎖結果:

結論:
此處表明,使用 List 跨線程操作,增減成員也需加鎖。否則會有各種問題。
有關線程集合安全訪問, 微軟在 .Net Framework 4 時,提供了線程安全集合命名空間:
System.Collections.Concurrent
