在.Net 4中,新增System.Collections.Concurrent 命名空間中提供多個線程安全集合類,這些類提供了很多有用的方法用於訪問集合中的元素,從而可以避免使用傳統的鎖(lock)機制等方式來處理併發訪問集合.因此當有多個線程併發訪問集合時,應首先考慮使用這些類代替 System.Collections 和 System.Collections.Generic 命名空間中的對應類型.具體如下:
1. ConcurrentQueue
表示線程安全的先進先出(FIFO)隊列.代碼如下:
ConcurrentQueue<int> sharedQueue = new ConcurrentQueue<int>();
for (int i = 0; i < 1000; i++)
{
sharedQueue.Enqueue(i);
}
int itemCount = 0;
Task[] tasks = new Task[10];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = new Task(() =>
{
while (sharedQueue.Count > 0)
{
int queueElement;
bool gotElement = sharedQueue.TryDequeue(out queueElement);
if (gotElement)
{
Interlocked.Increment(ref itemCount);
}
}
});
tasks[i].Start();
}
Task.WaitAll(tasks);
Console.WriteLine("Items processed:{0}", itemCount);
Console.WriteLine("Press Enter to finish");
Console.ReadLine();
該類有兩個重要的方法用來訪問隊列中的元素.分別是:
Ø TryDequeue 嘗試移除並返回位於隊列頭開始處的對象.
Ø TryPeek嘗試返回位於隊列頭開始處的對象但不將其移除.
現在,在多任務訪問集合元素時,我們只需要使用TryDequeue或TryPeek方法,就可以安全的訪問集合中的元素了.
2. ConcurrentStack
表示線程安全的後進先出(LIFO)棧.它也有幾個有用的方法,分別是:
Ø TryPeek:嘗試返回棧頂處的元素,但不移除.
Ø TryPop: 嘗試返回棧頂處的元素並移除.
Ø TryPopRange: 嘗試返回棧頂處開始指定範圍的元素並移除.
在訪問集合中的元素時,我們就可以上述方法.具體代碼實例於上面的ConcurrentQueue類似,就不重複了.
3. ConcurrentBag
實現的是一個無序的集合類.代碼如下:
ConcurrentBag<int> sharedBag = new ConcurrentBag<int>();
for (int i = 0; i < 1000; i++)
{
sharedBag.Add(i);
}
int itemCount = 0;
Task[] tasks = new Task[10];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = new Task(() =>
{
while(sharedBag.Count>0)
{
int queueElement;
bool gotElement = sharedBag.TryTake(out queueElement);
if (gotElement)
Interlocked.Increment(ref itemCount);
}
});
tasks[i].Start();
}
Task.WaitAll(tasks);
Console.WriteLine("Items processed:{0}", itemCount);
Console.WriteLine("Press Enter to finish");
Console.ReadLine();
該類有兩個重要的方法用來訪問隊列中的元素.分別是:
Ø TryTake 嘗試移除並返回位於隊列頭開始處的對象.
Ø TryPeek嘗試返回位於隊列頭開始處的對象但不將其移除.
4. ConcurrentDictionary
實現的是一個鍵-值集合類.它提供的方法有:
Ø TryAdd:嘗試向集合添加一個鍵-值
Ø TryGetValue:嘗試返回指定鍵的值.
Ø TryRemove:嘗試移除指定鍵處的元素.
Ø TryUpdate:嘗試更新指定鍵的值.
代碼如下:
class BankAccount
{
public int Balance
{
get;
set;
}
}
static void DictTest()
{
BankAccount account = new BankAccount();
ConcurrentDictionary<object, int> sharedDict = new ConcurrentDictionary<object, int>();
Task<int>[] tasks = new Task<int>[10];
for (int i = 0; i < tasks.Length; i++)
{
sharedDict.TryAdd(i, account.Balance);
tasks[i] = new Task<int>((keyObj) =>
{
int currentValue;
bool gotValue;
for (int j = 0; j < 1000; j++)
{
gotValue = sharedDict.TryGetValue(keyObj, out currentValue);
sharedDict.TryUpdate(keyObj, currentValue + 1, currentValue);
}
int result;
gotValue = sharedDict.TryGetValue(keyObj, out result);
if (gotValue)
{
return result;
}
else
{
throw new Exception(String.Format("No data item available for key {0}", keyObj));
}
}, i);
tasks[i].Start();
}
for (int i = 0; i < tasks.Length; i++)
{
account.Balance += tasks[i].Result;
}
Console.WriteLine("Expected value {0}, Balance: {1}", 10000, account.Balance);
Console.WriteLine("Press enter to finish");
Console.ReadLine();
}
通過上述提供的安全類,我們可以方便的併發訪問集合中的元素,而不需要以前的Synchronized方法或者lock(SyncRoot)等處理方式