我正在查看书中的示例代码,并遇到了以下代码(简化)。
在代码中,当调用Subscribe(T subscriber)
时,线程进入锁定部分。
然后,当锁内部的代码调用AddToSubscribers(T subscriber)
方法时,该方法有另一个锁。为什么这第二次锁是必要的?
public abstract class SubscriptionManager<T> where T : class
{
private static List<T> subscribers;
private static void AddToSubscribers(T subscriber)
{
lock (typeof(SubscriptionManager<T>))
{
if (subscribers.Contains(subscriber))
return;
subscribers.Add(subscriber);
}
}
public void Subscribe(T subscriber)
{
lock (typeof(SubscriptionManager<T>))
{
AddToSubscribers(subscriber);
}
}
}
答案 0 :(得分:10)
在这种情况下,它不是;但是,因为锁是可重入的,可以用来确保AddToSubscribers
的任何其他调用者都能观察到锁。实际上,出于这个原因,我会说“将其从Subscribe
中删除,然后让AddToSubscribers
执行锁定”。
然而!锁定Type
非常危险。一个字段会更安全:
// assuming static is correct
private static readonly object syncLock = new object();
和lock(syncLock)
。根据分配subscribers
的时间,您可能还会使用lock(subscribers)
(并且没有额外的字段)。
我还应该注意,将实例方法添加到静态状态非常......非同寻常; IMO Subscribe
应该是static
方法,因为它与当前实例无关。
答案 1 :(得分:4)
在您发布的代码中,没有必要。但话说回来,您发布的代码不完整 - 例如订阅者列表从未初始化。
锁定typeof(SubscriptionManager)可能也不是一个好主意 - 锁定subscribers
字段会更好 - 但需要初始化subscriber字段,例如
private static List<T> subscribers = new List<T>();
答案 2 :(得分:2)
您可能应该阅读该示例附近的内容并查看该书的内容。
对于那个特例 - 不,不需要第二次锁定。
注意:样本很危险,因为它锁定了公共对象(类型)。通常一个锁定特殊私有对象,因此外部代码无法通过错误地锁定同一对象而错误地引入死锁。
答案 3 :(得分:1)
我曾经遇到过一种情况,我不得不使用嵌套的锁。
我的情况是,第二个锁的功能可能是从其他地方调用的,因为它是一个静态函数。但是,对于您的情况,由于每个数据成员都属于一个实例而不是静态的,因此没有必要。