2013-03-12 61 views
-1
private static Thread thread; 
private static List<object> items = new List<object>(); 

static Program() 
{ 
    thread = new Thread(() => 
     { 
     foreach (var item in items) 
     { 
      item.Name = "ABC"; 
     } 
     Thread.Sleep(3600); 
     }); 
    thread.Start(); 
} 

private static void Main(string[] args) 
{ 
    var item = items.Where(i => i.Name == "ABC").FirstOrDefault(); 
    if(item != null) 
     { 
     items.Remove(item); 
     } 

} 

正如你看到的有螺紋得到應用開始開始使用列表清單上執行一些操作,和相同的列表由主線程 兩者之間。 共享列表線程

當新線程的foreach循環內的代碼正在執行並且同時foreach循環也得到執行時,它會拋出錯誤,無法修改列表。

任何想法如何克服這個問題?

謝謝

+5

您的代碼不修改列表,永遠......您的實際代碼在做什麼? – 2013-03-12 13:03:12

+3

即使您未使用任何線程,如果您正在枚舉它,也無法修改該列表。 – Matten 2013-03-12 13:03:40

+0

有評論//執行操作 – BreakHead 2013-03-12 13:04:05

回答

-1

您確定這是一個多線程問題嗎? List是相對線程安全的,Add和Remove方法都足夠快(據我所知)MS不認爲它是一個問題,不像Queue和ConcurrentQueue

注意,你不能修改Collection while while循環通過使用foreach這麼

List<int> integers = new List<int>(new int[] { 1,2,3,4,5,}); 
foreach(int i in integers) 
    integers.Add(1); // Will throw an InvalidOperationException 
+1

「A ** List **可以同時支持多個閱讀器,只要該集合沒有被修改。通過集合枚舉本質上不是一個線程安全的過程。在極少數情況下枚舉與一個或多個寫訪問,**確保線程安全的唯一方法是在整個枚舉期間鎖定集合**。爲了讓集合可以被多個線程訪問以進行讀取和寫入,您必須實現自己的同步。 – 2013-03-12 13:10:00

+1

通過讓多個併發作者是孩子玩耍來破壞列表。沒有「比較線程安全」的東西。這有點像「有點懷孕」。要麼它支持多個併發作者,要麼它不支持。 – 2013-03-12 13:36:59

+0

如果您認爲列表的添加或刪除實際上是線程安全的,那麼您就錯了。除非您添加/刪除列表中的最後一項(在這種情況下,它實際上會非常快),否則對於大型列表來說,這些操作的速度並不快。刪除第一個項目意味着*列表中的每一個項目*都需要向上移動一個位置。如果你沒有看到這可能會帶來什麼負面影響,或者如何做得如此之快以至於看起來很原子,那麼我建議你遠離任何多線程編程。 – Servy 2013-03-12 13:54:09

0

你正在談論的話題是線程Safeness

要做到這一點,就必須使用synchronized方法

編輯:

很抱歉,一個當然C#,看看這裏: http://msdn.microsoft.com/en-us/library/ms173179.aspx

它幾乎是一樣的Java同步,你只需要鎖定爲你使用它的期限對象,這樣,你的線程保持安全

要知道,當物體被鎖定,所有其他線程試圖訪問該對象將不得不等待,這可能會導致死鎖

+0

這是關於C#,而不是java。即使概念是相同的C#不知道'synchronized'關鍵字。 – Matten 2013-03-12 13:13:06

0

在你的榜樣,你是修改集合在enumerati上。但是,您正在修改枚舉之外的集合,如果在枚舉過程中發生這種情況,您將得到例外InvalidOperationException: Collection was modified

MSDN

一個列表(T)可以支持多個讀者同時,只要 集合不會被改動。枚舉枚舉通過 本質上不是一個線程安全的過程。在 枚舉與一個或多個寫入訪問競爭的罕見情況下,確保線程安全的唯一方法是在整個 枚舉期間鎖定集合。要允許通過多個 線程訪問該集合以進行讀寫,您必須實現自己的 同步。

private static Thread thread; 
private static List<object> items = new List<object>(); 
private Object theLock = new Object(); 

static Program() 
{ 
    thread = new Thread(() => 
    { 
     lock(theLock) 
     { 
     foreach (var item in items) 
     { 
      item.Name = "ABC"; 
     } 
     } 
     Thread.Sleep(3600); 
    }); 
    thread.Start(); 
} 

private static void Main(string[] args) 
{ 
    lock(theLock) 
    { 
    var item = items.Where(i => i.Name == "ABC").FirstOrDefault(); 
    if(item != null) 
    { 
     items.Remove(item); 
    } 
    } 
}