測試條件:
開啟2個並行執行任務,往同一個list對象寫入值
測試代碼:

static int maxNum = 1000000; static List<int> list = new List<int>(); static void Main(string[] args) { //迭代次數 int iterationNum = 3; CodeTimer.Initialize(); CodeTimer.Time("List是否是線程安全的呢?", iterationNum, new Action(ListIsThreadSafe)); //Console.Write(sbIsThreadSafe.ToString()); Console.Read(); } private static void ListIsThreadSafe() { Parallel.For(1, maxNum / 2, (i) => { list.Add(i); }); Parallel.For(maxNum / 2 + 1, maxNum, (i) => { list.Add(i); }); }
測試結果:
測試結論:
之所以會造成以上的結果是因為list對象不是線程安全。那該怎么辦呢?
這時我們需要使用System.Collections.Concurrent命名空間下的類型來用於並行循環體內。
類 |
說明 |
BlockingCollection<T> |
為實現 IProducerConsumerCollection<T> 的線程安全 集合提供阻止和限制功能。 |
ConcurrentBag<T> |
表示對象的線程安全的無序集合。 |
ConcurrentDictionary<TKey, TValue> |
表示可由多個線程同時訪問的鍵值對的線程安全集合。 |
ConcurrentQueue<T> |
表示線程安全的先進先出 (FIFO) 集合。 |
ConcurrentStack<T> |
表示線程安全的后進先出 (LIFO) 集合。 |
OrderablePartitioner<TSource> |
表示將一個可排序數據源拆分成多個分區的特定方式。 |
Partitioner |
提供針對數組、列表和可枚舉項的常見分區策略。 |
Partitioner<TSource> |
表示將一個數據源拆分成多個分區的特定方式。 |
我們再來進行一次測試。
測試代碼:

static int maxNum = 1000000; static ConcurrentQueue<int> safeList = new ConcurrentQueue<int>(); static void Main(string[] args) { //迭代次數 int iterationNum = 3; CodeTimer.Initialize(); CodeTimer.Time("ConcurrentQueue是否是線程安全的呢?", iterationNum, new Action(ListIsThreadSafe)); //Console.Write(sbIsThreadSafe.ToString()); Console.Read(); } private static void ListIsThreadSafe() { Parallel.For(1, maxNum / 2, (i) => { safeList.Enqueue(i); }); Parallel.For(maxNum / 2 + 1, maxNum, (i) => { safeList.Enqueue(i); }); }
測試結果:
測試結論:
ConcurrentQueue是線程安全的。在遇到多線程和並行開發時應該使用ConcurrentQueue而不是List.
疑問:為了確保對象線程安全,系統底層實現機制必定是要使用對象加鎖和解鎖的功能來確保對象安全,那么加鎖和解鎖是否會對性能造成影響呢?
我們再來進行一組測試:
測試條件:
(1)對100萬個數據進行普通的循環運算然后添加到List集合對象中。
(2)對100萬個數據進行並行循環運算然后添加到ConcurrentQueue集合對象中。
測試代碼:

static int maxNum = 1000000; static List<BigInteger> list = new List<BigInteger>(); static ConcurrentQueue<BigInteger> safeList = new ConcurrentQueue<BigInteger>(); static void Main(string[] args) { //迭代次數 int iterationNum = 3; CodeTimer.Initialize(); CodeTimer.Time("普通的循環運算", iterationNum, new Action(NormalCompute)); CodeTimer.Time("並行循環運算_1", iterationNum, new Action(ParallelCompute_1)); CodeTimer.Time("並行循環運算_2", iterationNum, new Action(ParallelCompute_2)); Console.Read(); } private static void NormalCompute() { for (int i = 1; i <= maxNum; i++) { Math.Pow(i, i + 1); list.Add(new BigInteger(i)); } } private static void ParallelCompute_1() { Parallel.For(1, maxNum, (i) => { Math.Pow(i, i + 1); safeList.Enqueue(new BigInteger(i)); }); } private static void ParallelCompute_2() { Parallel.For(1, maxNum / 2, (i) => { Math.Pow(i, i + 1); safeList.Enqueue(new BigInteger(i)); }); Parallel.For(maxNum / 2 + 1, maxNum, (i) => { Math.Pow(i, i + 1); safeList.Enqueue(new BigInteger(i)); }); }
測試結果:
測試結論:
和我預期的結論是一樣的,並行方式所耗費的時間更加的長。線程安全的加鎖和解鎖對性能的影響還是比較大的。