锁定私有静态对象

时间:2013-10-28 21:48:48

标签: c# multithreading

我想知道以下哪个代码最好:

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);
            ...
        }
    }
}

3 个答案:

答案 0 :(得分:9)

迈克斯特罗贝尔的建议是很好的建议。总结一下:

  • 仅锁定专门用作锁定的对象
  • 这些锁定对象应该是在声明中初始化的私有只读字段。
  • 不要尝试滚动自己的线程安全延迟初始化。使用Lazy<T>类型;它是由知道自己在做什么的专家设计的。
  • 锁定对受保护变量的所有访问。
  • 当以下两个条件中的两者都成立时,违反这些合理的指导原则:(1)您有经验证明的客户影响性能问题以及使用更复杂的低锁线程的可靠证据安全系统是解决问题的唯一合理方案,(2)您是处理器优化对低锁代码影响的领先专家。例如,如果您是Grant Morrison或Joe Duffy。

答案 1 :(得分:5)

两段代码等效。前者确保所有线程始终使用相同的锁对象。后者锁定了一个延迟初始化的对象,并且绝对没有阻止_instance字典的多个实例化,导致内容丢失。

锁的目的是什么?服务是否是为了保证字典的单初始化?忽略它在第二个示例中未能完成此操作,如果这是其唯一的预期目的,那么您可以考虑简单地使用Lazy<T>类或双重检查锁定模式。

但由于这是一个静态成员(并且似乎没有捕获外部泛型参数),因此可能每个AppDomain只会实例化一次。在这种情况下,只需将其标记为readonly并在声明中初始化它。你可能不会这么节省。

由于您关注最佳实践:您应该从不在可变值上使用lock构造;这适用于静态和实例字段,以及本地。锁定 volatile 字段是特别不良做法,因为该关键字的存在表明您期望要更改的基础值。如果您要锁定某个字段,它应该几乎总是readonly字段。锁定方法结果也被认为是不好的做法;这也适用于属性,因为属性实际上是一对特殊命名的存取方法。

答案 2 :(得分:3)

如果你没有将Instance暴露给其他类,第二种方法是可以的(但不等同)。最好将锁对象保存为将其用作锁对象的类。只有当其他类也可以将此对象作为锁定对象时,您可能会遇到问题。

(为了完整性和@Scott张伯伦评论:) 这假定Instance的类没有使用lock (this),而相反代表不良做法。

尽管如此,该物业可能会出现问题。 null合并运算符被编译为空检查+赋值...因此您可能遇到竞争条件。您可能希望read more了解此问题。但是如果可能的话,还要考虑删除延迟初始化。