本文以List做爲操做對象
MSDN官方給出的List的線程安全的說法:
此類型的公共靜態成員是線程安全的。但不能保證任何實例成員是線程安全的。
只要不修改該集合,List 就能夠同時支持多個閱讀器。經過集合枚舉在本質上不是一個線程安全的過程。在枚舉與一個或多個寫訪問競爭的罕見狀況下,確保線程安全的惟一方法是在整個枚舉期間鎖定集合。若要容許多個線程訪問集合以進行讀寫操做,則必須實現本身的同步。
若是不進行同步操做?
假如一個線程進行刪除操做,一個線程進行遍歷操做,那麼在遍歷過程當中,集合被修改,會致使出現InvalidOperationException的異常,提示:集合已修改;可能沒法執行枚舉操做。
如何同步,保證遍歷的安全
這裏使用了臨界區,互斥鎖來保證線程遍歷過程的安全,示例代碼以下:數組
1 using System; 2 using System.Collections.Generic; 3 using System.Threading; 4 5 namespace ConsoleApp 6 { 7 class Program 8 { 9 public static List<string> simpleList = new List<string>(); 10 11 public static void Main(string[] args) 12 { 13 // 臨界區對象 14 object lockObj = new object(); 15 16 // 向List中添加測試數據 17 string[] data = { "1", "2", "3", "4", "5", "6", "7", "8" }; 18 simpleList.AddRange(data); 19 // 此線程用於遍歷數組 20 new Thread(new ThreadStart(() => 21 { 22 // 用於同步,進入臨界區,只有遍歷完,釋放臨界區對象的互斥鎖,才能進行寫操做 23 lock (lockObj) 24 { 25 foreach (var item in simpleList) 26 { 27 Console.WriteLine(item); 28 Thread.Sleep(500); 29 } 30 } 31 })).Start(); 32 // 此線程執行刪除操做 33 new Thread(new ThreadStart(() => 34 { 35 lock (lockObj) 36 { 37 simpleList.RemoveAt(0); 38 Console.WriteLine("rm 1"); 39 Thread.Sleep(500); 40 simpleList.RemoveAt(0); 41 Console.WriteLine("rm 2"); 42 } 43 })).Start(); 44 45 Console.ReadLine(); 46 } 47 } 48 }