这段时间我是不是一直把锁弄错了
本文关键字:一直 是不是 锁弄 错了 段时间 时间 | 更新日期: 2023-09-27 18:25:41
我正在阅读这篇关于Singleton中线程安全的文章,它让我觉得我不理解lock
方法。
在第二个版本中,作者有这样的:
public sealed class Singleton
{
private static Singleton instance = null;
private static readonly object padlock = new object();
Singleton()
{
}
public static Singleton Instance
{
get
{
lock (padlock)
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
}
而我会做一些更像这样的事情:
public sealed class Singleton
{
private static Singleton instance = null;
Singleton()
{
}
public static Singleton Instance
{
get
{
lock (instance)
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
}
为什么要使用padlock
对象,而不是锁定要锁定的实际对象?
在锁定对象之前,第一次访问Instance
属性时会发生什么?
(提示:lock(null)
爆炸…)
作为一项单独的措施,我几乎总是避免锁定"实际对象",因为通常情况下,该引用可能会暴露在其他代码中,我不一定知道会锁定什么。即使您的版本确实有效,如果一些外部代码写道:
// Make sure only one thread is ever in this code...
lock (Singleton.Instance)
{
// Do stuff
}
现在,在执行代码时,其他人甚至无法获取实例,因为它们最终会被getter阻塞。getter中的锁并不意味着要防止这种情况——它只意味着要阻止getter中的多次访问。
对锁的控制越严格,就越容易推理并避免死锁。
我偶尔锁定"正常"对象,如果:
- 我不会在该类之外公开该引用
- 我相信类型本身(当然,它总是引用
this
)不会锁定自己
(当然,所有这些都是避免锁定this
的原因…)
从根本上说,我认为允许锁定任何对象的想法在Java中都是个坏主意,在.NET中复制它也是个坏主意:(
锁定this
或任何其他非私有对象是危险的,因为如果其他人也试图使用该对象进行同步,则会导致死锁。
这种可能性不大,这就是为什么人们可以养成多年不被咬的习惯。但这仍然是可能的,并且object
的私有实例的成本可能不足以证明运行该风险是合理的。
对于锁定,您可以使用任何类型的对象,类型其实并不重要,它只是用作一个标志,一次只有一个线程可以容纳它。
当然,可以将其作为锁定参数。但我想不推荐使用它的主要原因是其他类也可以使用您类的实例作为锁定对象,这可能会导致严重的问题