我在以下代码中使用.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; } }