我想知道以下哪个代码最好:
private static volatile OrderedDictionary _instance;
private static readonly Object SyncLock = new Object();
private static OrderedDictionary Instance
{
get { return _instance ?? (_instance = new OrderedDictionary()); }
}
public static Mea Add(Double pre, Double rec)
{
lock (SyncLock)
{
...
}
}
或者它是否可以更好IMO只使用以下内容?
private static volatile OrderedDictionary _instance;
private static OrderedDictionary Instance
{
get { return _instance ?? (_instance = new OrderedDictionary()); }
}
public static Mea Add(Double pre, Double rec)
{
lock (Instance)
{
...
}
}
根据Mike Strobel的回答,我做了以下更改:
public static class Meas
{
private static readonly OrderedDictionary Instance = new OrderedDictionary();
private static readonly Object SyncLock = new Object();
public static Mea Add(Double pre, Double rec)
{
lock (SyncLock)
{
Instance.Add(pre, rec);
...
}
}
}
答案 0 :(得分:9)
Lazy<T>
类型;它是由知道自己在做什么的专家设计的。答案 1 :(得分:5)
两段代码不等效。前者确保所有线程始终使用相同的锁对象。后者锁定了一个延迟初始化的对象,并且绝对没有阻止_instance
字典的多个实例化,导致内容丢失。
锁的目的是什么?服务是否是为了保证字典的单初始化?忽略它在第二个示例中未能完成此操作,如果这是其唯一的预期目的,那么您可以考虑简单地使用Lazy<T>
类或双重检查锁定模式。
但由于这是一个静态成员(并且似乎没有捕获外部泛型参数),因此可能每个AppDomain只会实例化一次。在这种情况下,只需将其标记为readonly
并在声明中初始化它。你可能不会这么节省。
由于您关注最佳实践:您应该从不在可变值上使用lock
构造;这适用于静态和实例字段,以及本地。锁定 volatile 字段是特别不良做法,因为该关键字的存在表明您期望要更改的基础值。如果您要锁定某个字段,它应该几乎总是readonly
字段。锁定方法结果也被认为是不好的做法;这也适用于属性,因为属性实际上是一对特殊命名的存取方法。
答案 2 :(得分:3)
如果你没有将Instance
暴露给其他类,第二种方法是可以的(但不等同)。最好将锁对象保存为将其用作锁对象的类。只有当其他类也可以将此对象作为锁定对象时,您可能会遇到问题。
(为了完整性和@Scott张伯伦评论:)
这假定Instance
的类没有使用lock (this)
,而相反代表不良做法。
尽管如此,该物业可能会出现问题。 null合并运算符被编译为空检查+赋值...因此您可能遇到竞争条件。您可能希望read more了解此问题。但是如果可能的话,还要考虑删除延迟初始化。