MSDN文档是这么说的
public class SomeObject
{
public void SomeOperation()
{
lock(this)
{
//Access instance variables
}
}
}
是“如果实例可以公开访问,则会出现问题”。我想知道为什么?这是因为锁持有的时间比需要的时间长吗?还是有更阴险的原因?
MSDN文档是这么说的
public class SomeObject
{
public void SomeOperation()
{
lock(this)
{
//Access instance variables
}
}
}
是“如果实例可以公开访问,则会出现问题”。我想知道为什么?这是因为锁持有的时间比需要的时间长吗?还是有更阴险的原因?
当前回答
你可以建立一个规则,规定一个类可以有锁定'this'或类中代码实例化的任何对象的代码。所以只有不遵循这个模式才会有问题。
如果您想保护自己不受不遵循此模式的代码的影响,那么接受的答案是正确的。但如果遵循这个模式,那就不是问题。
锁的优点是效率高。如果你有一个简单的“值对象”,它只包含一个值。它只是一个包装器,它被实例化了数百万次。通过要求仅为锁定而创建一个私有同步对象,基本上使对象的大小增加了一倍,分配的数量也增加了一倍。当性能很重要时,这是一个优势。
当您不关心分配数量或内存占用时,出于其他答案中指出的原因,避免锁定(这)是可取的。
其他回答
抱歉,伙计们,我不同意锁定这个可能会导致僵局的说法。你混淆了两件事:僵局和饥饿。
如果不中断其中一个线程,就无法取消死锁,因此进入死锁后就无法退出 饥饿将在其中一个线程完成其工作后自动结束
这里有一张图可以说明两者的区别。
结论 如果线程饥饿对您来说不是问题,您仍然可以安全地使用lock(this)。你仍然需要记住,当线程使用lock(this)饿死线程时,它将以锁定对象的锁结束,它最终将以永远饥饿结束;)
请参考下面的链接,它解释了为什么锁(这)不是一个好主意。
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"); } }
因为如果人们可以获得你的对象实例(即:你的this)指针,那么他们也可以尝试锁定相同的对象。现在他们可能没有意识到您在内部锁定了这个,所以这可能会导致问题(可能是死锁)
除此之外,这也是一种糟糕的做法,因为它锁定了“太多”
例如,你可能有一个成员变量List<int>,你唯一需要锁定的就是这个成员变量。如果你在你的函数中锁定了整个对象,那么其他调用这些函数的东西将被阻塞等待锁定。如果这些函数不需要访问成员列表,则会导致其他代码等待,并毫无理由地降低应用程序的速度。
...同样的论点也适用于这个结构:
lock(typeof(SomeObject))