MSDN文档是这么说的

public class SomeObject
{
  public void SomeOperation()
  {
    lock(this)
    {
      //Access instance variables
    }
  }
}

是“如果实例可以公开访问,则会出现问题”。我想知道为什么?这是因为锁持有的时间比需要的时间长吗?还是有更阴险的原因?


当前回答

你可以建立一个规则,规定一个类可以有锁定'this'或类中代码实例化的任何对象的代码。所以只有不遵循这个模式才会有问题。

如果您想保护自己不受不遵循此模式的代码的影响,那么接受的答案是正确的。但如果遵循这个模式,那就不是问题。

锁的优点是效率高。如果你有一个简单的“值对象”,它只包含一个值。它只是一个包装器,它被实例化了数百万次。通过要求仅为锁定而创建一个私有同步对象,基本上使对象的大小增加了一倍,分配的数量也增加了一倍。当性能很重要时,这是一个优势。

当您不关心分配数量或内存占用时,出于其他答案中指出的原因,避免锁定(这)是可取的。

其他回答

因为如果人们可以获得你的对象实例(即:你的this)指针,那么他们也可以尝试锁定相同的对象。现在他们可能没有意识到您在内部锁定了这个,所以这可能会导致问题(可能是死锁)

除此之外,这也是一种糟糕的做法,因为它锁定了“太多”

例如,你可能有一个成员变量List<int>,你唯一需要锁定的就是这个成员变量。如果你在你的函数中锁定了整个对象,那么其他调用这些函数的东西将被阻塞等待锁定。如果这些函数不需要访问成员列表,则会导致其他代码等待,并毫无理由地降低应用程序的速度。

这里有一个更简单的例子(来自这里的问题34),为什么锁(this)是不好的,并且当你的类的消费者也试图锁定对象时可能会导致死锁。 下面,三个线程中只有一个线程可以继续,其他两个线程处于死锁状态。

class SomeClass { public void SomeMethod(int id) { **lock(this)** { while(true) { Console.WriteLine("SomeClass.SomeMethod #" + id); } } } } class Program { static void Main(string[] args) { SomeClass o = new SomeClass(); lock(o) { for (int threadId = 0; threadId < 3; threadId++) { Thread t = new Thread(() => { o.SomeMethod(threadId); }); t.Start(); } Console.WriteLine(); }

为了解决这个问题,这家伙使用了Thread。TryMonitor(带超时)而不是lock:

班长。TryEnter(temp, millisecondsTimeout, ref lockWasTaken); 如果(lockWasTaken) { doAction (); } 其他的 { 抛出新的异常(" cannot get lock"); }

https://blogs.appbeat.io/post/c-how-to-lock-without-deadlocks

...同样的论点也适用于这个结构:

lock(typeof(SomeObject))

你可以建立一个规则,规定一个类可以有锁定'this'或类中代码实例化的任何对象的代码。所以只有不遵循这个模式才会有问题。

如果您想保护自己不受不遵循此模式的代码的影响,那么接受的答案是正确的。但如果遵循这个模式,那就不是问题。

锁的优点是效率高。如果你有一个简单的“值对象”,它只包含一个值。它只是一个包装器,它被实例化了数百万次。通过要求仅为锁定而创建一个私有同步对象,基本上使对象的大小增加了一倍,分配的数量也增加了一倍。当性能很重要时,这是一个优势。

当您不关心分配数量或内存占用时,出于其他答案中指出的原因,避免锁定(这)是可取的。

如果可以公开访问实例,就会出现问题,因为可能有其他请求正在使用相同的对象实例。最好使用私有/静态变量。