4

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

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

3 回答 3

9

Mike Strobel 的建议是很好的建议。总结一下:

  • 仅锁定专门用作锁定的对象。
  • 这些锁定对象应该是在其声明中初始化的私有只读字段。
  • 不要尝试滚动您自己的线程安全延迟初始化。使用Lazy<T>类型;它是由知道自己在做什么的专家设计的。
  • 锁定对受保护变量的所有访问。
  • 当以下两个条件都为真时,违反这些明智的指导方针:(1)您有一个经验证明的影响客户的性能问题,并且有充分的证据表明使用更复杂的低锁线程安全系统是解决该问题的唯一合理解决方案,并且 (2) 您是处理器优化对低锁代码影响的领先专家。例如,如果您是格兰特·莫里森或乔·达菲。
于 2013-10-28T22:19:14.167 回答
5

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

锁的目的是什么?除了保证字典的单一初始化之外,它是否还有其他目的?忽略它在第二个示例中未能实现这一点,如果这是它的唯一预期目的,那么您可以考虑简单地使用Lazy<T>类或双重检查锁定模式。

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

由于您关心最佳实践:您永远不lock应该在可变值上使用构造;这适用于静态和实例字段,以及本地。锁定volatile字段是特别糟糕的做法,因为该关键字的存在表明您希望基础值发生变化。如果你要锁定一个字段,它应该几乎总是一个字段。锁定方法结果也被认为是不好的做法;这也适用于属性,因为属性实际上是一对特殊命名的访问器方法。readonly

于 2013-10-28T21:57:35.207 回答
3

如果您不Instance向其他类公开,则第二种方法是可以的(但不是等效的)。最好的做法是让锁对象对使用它作为锁对象的类来说是私有的。只有当其他类也可以将此对象作为锁定对象时,您可能会遇到问题。

(为了完整性和关于@Scott Chamberlain 的评论:)这假设该类Instance没有使用lock (this)相反的代表不好的做法。

然而,该物业可能会产生问题。空合并运算符被编译为空检查+赋值...因此您可能会遇到竞争条件。您可能想了解更多有关此内容的信息。但如果可能的话,还要考虑完全删除延迟初始化。

于 2013-10-28T21:50:01.817 回答