MSDN文档是这么说的

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

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


当前回答

这里也有一些关于这个的很好的讨论:这是互斥锁的正确使用吗?

其他回答

请参考下面的链接,它解释了为什么锁(这)不是一个好主意。

https://learn.microsoft.com/en-us/dotnet/standard/threading/managed-threading-best-practices

所以解决方案是添加一个私有对象,例如,lockObject到类中,并将代码区域放在lock语句中,如下所示:

lock (lockObject)
{
...
}

以下是不建议使用的原因。

短版: 考虑下面的代码片段:

object foo = new Object(); 
object bar = foo; 

lock(foo)
{
  lock(bar){}
}  

这里,foo和bar引用的是导致死锁的同一个对象实例。这是现实中可能发生的事情的简化版本。

长版: 为了根据下面的代码片段更详细地解释它,假设您编写了一个类(在本例中为SomeClass),并且类的使用者(名为“John”的编码器)希望获得类实例(在本例中为someObject)上的锁。他遇到死锁是因为他在实例someObject上获得了一个锁,在这个锁中他调用了该实例的一个方法(SomeMethod()),该方法在内部获得了同一个实例上的锁。

I could have written the following example with or without Task/Thread and the gist of deadlock still remains the same. To prevent bizarre situation where the main Thread finishes while its children are still running, I used .Wait(). However, in long-running-tasks or situation where a code-snippet executes more frequently, you would definitely see the same behavior. Although John applied a bad practice of using an instance of a class as a lock-object, but we (as the developer of a classlibrary SomeClass) should deter such situation simple by not using this as a lock-object in our class. Instead, we should declare a simple private field and use that as our lock-object. using System; using System.Threading; using System.Threading.Tasks; class SomeClass { public void SomeMethod() { //NOTE: Locks over an object that is already locked by the caller. // Hence, the following code-block never executes. lock (this) { Console.WriteLine("Hi"); } } } public class Program { public static void Main() { SomeClass o = new SomeClass(); lock (o) { Task.Run(() => o.SomeMethod()).Wait(); } Console.WriteLine("Finish"); } }

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

抱歉,伙计们,我不同意锁定这个可能会导致僵局的说法。你混淆了两件事:僵局和饥饿。

如果不中断其中一个线程,就无法取消死锁,因此进入死锁后就无法退出 饥饿将在其中一个线程完成其工作后自动结束

这里有一张图可以说明两者的区别。

结论 如果线程饥饿对您来说不是问题,您仍然可以安全地使用lock(this)。你仍然需要记住,当线程使用lock(this)饿死线程时,它将以锁定对象的锁结束,它最终将以永远饥饿结束;)

这里有一个更简单的例子(来自这里的问题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