最近在做一些代碼整理工作,涉及到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