我在以下代码中使用.NET 4中的ConcurrentDictionary和ConcurrentQueue类.
这段代码是线程安全的吗?如果没有,我怎样才能使它成为线程安全的?
- public class Page
- {
- public string Name {get; set; }
- }
- public class PageQueue
- {
- private ConcurrentDictionary<int,ConcurrentQueue<Page>> pages =
- new ConcurrentDictionary<int,ConcurrentQueue<Page>>();
- public void Add(int id,Page page)
- {
- if (!this.pages.ContainsKey(id))
- this.pages[id] = new ConcurrentQueue<Page>();
- this.pages[id].Enqueue(page);
- }
- public Page GetAndRemove(int id)
- {
- Page lp = null;
- if(this.pages.ContainsKey(id))
- this.pages[id].TryDequeue(out lp);
- return lp;
- }
- }
演示:
- public class Demo
- {
- public void RunAll()
- {
- for (int i = 0; i < 10; i++)
- Task.Factory.StartNew(() => Run());
- }
- public void Run()
- {
- PageQueue pq = new PageQueue();
- pq.Add(1,new Page());
- pq.GetAndRemove(1);
- }
- }
解决方法
正如@Femaref正确指出的那样,代码中存在一些缺陷.我建议你利用
ConcurrentDictionary<K,V>提供的许多方法使代码线程安全而不需要锁定语句:
- public class PageQueue
- {
- private ConcurrentDictionary<int,ConcurrentQueue<Page>>();
- public void Enqueue(int id,Page page)
- {
- var queue = this.pages.GetOrAdd(id,_ => new ConcurrentQueue<Page>());
- queue.Enqueue(page);
- }
- public bool TryDequeue(int id,out Page page)
- {
- ConcurrentQueue<Page> queue;
- if (this.pages.TryGetValue(id,out queue))
- {
- return queue.TryDequeue(out page);
- }
- page = null;
- return false;
- }
- }