我有多个队列正在被多个线程访问。为了实现线程安全,我做了以下几点:
private static Dictionary<string, Queue<string>> MyQueues = new Dictionary<string, Queue<string>>();
public static string GetNextQueueElementForKey(string key)
{
string res = string.Empty;
if (MyQueues.Keys.Contains(key))
{
Queue<string> queue = MyQueues[key];
lock (queue)
{
if (queue.Count() > 0)
{
res = queue.Dequeue();
}
}
}
return res;
}
我也可以锁定MyQueues
,但是我会锁定超过必要的数量。所以我的问题是,如果锁定字典中包含的对象将起作用 - 假设一个键的值(队列)永远不会改变。
答案 0 :(得分:7)
你可以 - 但我通常不会。就个人而言,我通常会尝试锁定那些不用于其他任何事情的普通System.Object
实例,理想情况下甚至不会暴露于除锁定类之外的任何代码。这样你就可以绝对确定没有别的东西可以锁定。
在这种情况下,看起来你已经控制了队列,所以你知道它们不会被其他代码使用,但可能 Queue<T>
内的代码将会锁定this
。这可能不是这样,但这是我会担心的事情。
从根本上说,我希望.NET没有采用Java的“每个对象的监视器”的方法 - 我希望Monitor
是一个可实例化的类。
(我假设你实际上只是从多个线程的字典中读取 ?使用字典进行多线程读/写是不安全的。)
答案 1 :(得分:2)
它是字典中的元素这一事实在很大程度上是无关紧要的 - 只要它是一个引用类型(Queue<string>
是) - 然后每个队列,当从字典,每次都是相同的object
实例。这意味着它可以完全合理地锁定每个队列级别。
所以基本上:是的,只要Enqueue
执行相同的每队列锁定,这应该可以正常工作。正如乔恩所说 - 无论你应该这样做是另一个问题。
就个人而言,我仍然认为Monitor
应该是非静态类型,并且您只能锁定Monitor
个实例,而不是object
。< / p>
答案 2 :(得分:1)
所以我的问题是,如果锁定字典中包含的对象将起作用 - 假设一个键的值(队列)永远不会改变。
在这里查看您的代码:
lock (queue) {
if (queue.Count() > 0) {
res = queue.Dequeue();
}
}
你可以,但我不这样做。您应该never lock on the object itself,因为您可能会与其他代码线程竞争,这些代码将锁定同一个对象,包括Queue<T>
本身(谁可以锁定this
)。
因此,至少应该为每个队列创建一个专用的锁定对象。
但是,您有没有使用ConcurrentQueue<T>
的原因?这是最简单的解决方案,并将负责任的问题转移到框架上。