对多种方法使用相同的锁

时间:2010-12-23 20:12:11

标签: c# .net multithreading locking thread-safety

到目前为止,我对多种方法使用相同的锁没有任何问题,但我想知道下面的代码是否可能确实存在我不知道的问题(性能?):

private static readonly object lockObj = new object();

public int GetValue1(int index)
{
    lock(lockObj)
    {
        // Collection 1 read and/or write
    }
}

public int GetValue2(int index)
{
    lock(lockObj)
    {
        // Collection 2 read and/or write
    }
}

public int GetValue3(int index)
{
    lock(lockObj)
    {
        // Collection 3 read and/or write
    }
}

无论如何,3种方法和集合都无关。

此外,如果单身人士(在Instance属性中)也使用lockObj这会是一个问题吗?

编辑:澄清我在Singleton类中使用相同锁对象的问题:

private static readonly object SyncObject = new object();

public static MySingleton Instance
{
    get
    {
        lock (SyncObject)
        {
          if (_instance == null)
          {
              _instance = new MySingleton();
          }
        }
        return _instance;
    }
}

public int MyMethod()
{
      lock (SyncObject)
      {
           // Read or write
      }  
}

这会导致问题吗?

5 个答案:

答案 0 :(得分:16)

如果方法与您所说的无关,则为每个方法使用不同的锁;否则它效率低下(因为没有理由让不同的方法锁定同一个对象,因为它们可以安全地同时执行)。

此外,似乎这些是锁定在静态对象上的实例方法 - 这是有意的吗?我有一种感觉,这是一个错误;实例方法应该(通常)只锁定实例字段。

关于Singleton设计模式:

虽然锁定对于那些人来说是安全的,但更好的做法是对字段进行延迟初始化,如下所示:

private static object sharedInstance;
public static object SharedInstance
{
     get
     {
          if (sharedInstance == null)
              Interlocked.CompareExchange(ref sharedInstance, new object(), null);
          return sharedInstance;
     }
}

这种方式更快一些(因为互锁方法更快,并且因为初始化延迟了),但仍然是线程安全的。

答案 1 :(得分:8)

通过在所有这些方法中使用相同的对象lock,您可以序列化对所有线程中代码的所有访问

这就是......运行GetValue1()的代码将阻止不同线程中的其他代码运行GetValue2(),直到完成为止。如果你添加更多锁定在同一个对象实例上的代码,你最终会在某个时候有效地使用单线程应用程序。

答案 2 :(得分:5)

共享锁可锁定其他不相关的呼叫

如果使用相同的锁,则锁定一个方法也会不必要地锁定其他方法。如果他们根本不相关,那么这是一个问题,因为他们必须等待彼此。他们不应该这样做。

瓶颈

当经常调用这些方法时,这可能会造成瓶颈。使用单独的锁定它们可以独立运行,但共享相同的锁定意味着它们必须等待锁定按需要更频繁地释放(实际上三次更频繁)。

答案 3 :(得分:2)

要创建线程安全的单例,请使用this technique 你不需要锁。

一般情况下,应尽可能少地使用每个锁 更多的方法锁定同一个东西,当你真的不需要时,你可能最终会等待它。

答案 4 :(得分:0)

好问题。使锁具有更细粒度而不是更粗粒度的优缺点,一个极端是针对每个数据段的单独锁,另一个极端是针对整个程序的一个锁。正如其他帖子所指出的那样,重用相同锁的缺点通常是您可能会获得较少的并发性(尽管取决于情况,您并不会获得较少的并发性。)

但是,使用更多锁的缺点通常是使死锁更有可能。涉及到的锁越多,死锁的方法就越多。例如,在单独的线程中同时获取两个锁,但以相反的顺序获取两个锁是潜在的死锁,如果只涉及一个锁,则不会发生。当然,有时您可以通过将一个锁分成两个来修复死锁,但是通常更少的锁意味着更少的死锁。还增加了具有更多锁的代码复杂性。

通常,这两个因素需要加以平衡。如果不引起任何并发问题,通常为每个类使用一个锁即可。实际上,这样做是一种称为监视器的设计模式。

我想说的最佳实践是,出于代码简单的考虑,倾向于减少锁,如果有充分的理由(例如并发,或者更简单或解决死锁的情况),则增加附加锁。