線程安全集合類

在.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<objectint> sharedDict = new ConcurrentDictionary<objectint>();

 

            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)等處理方式
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章