我一直在做错锁吗?

Mat*_*nde 4 c# multithreading locking

我正在阅读这篇关于Singletons中线程安全的文章,它让我觉得我不理解这个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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然我会做更像这样的事情:

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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么要使用padlock对象,而不是锁定要锁定的实际对象?

Jon*_*eet 13

Instance在您有一个锁定对象之前,您第一次访问该属性时会发生什么?

(提示:lock(null)砰的一声......)

作为一个单独的措施,我几乎总是避免锁定"实际对象" - 因为通常可能存在其他代码,该引用被暴露给我,并且我不一定知道它将锁定什么.即使您的版本确实有效,如果某些外部代码写入会发生什么:

// Make sure only one thread is ever in this code...
lock (Singleton.Instance)
{
    // Do stuff
}
Run Code Online (Sandbox Code Playgroud)

现在没有其他人甚至可以在代码执行时获取实例,因为它们最终会在getter中被阻塞.吸气剂中的锁定并不意味着防止它 - 它只是为了防止吸气剂内的多次进入.

你可以越紧密地控制你的锁,就越容易理解它们并避免死锁.

如果出现以下情况,我偶尔会对"普通"对象进行锁定:

  • 我没有在那个课程之外暴露那个参考
  • 我有信心,类型本身(this当然总是有一个引用)不会锁定自己.

(所有这些都是避免锁定的理由this,当然......)

从根本上说,我认为允许你锁定任何对象的想法在Java中是一个坏主意,并且在.NET中复制它是一个糟糕的举动:(

  • @MattGrande:我认为你以迂回的方式得到的是你想要锁定变量**,因为当然这就是你要变异的东西.这很有道理; 如果你想让人们离开你的浴室,你就可以在浴室里锁上*; 你不要把锁放在房子的其他地方,并要求人们在进入浴室之前将其锁定.虽然这在概念上是有道理的,但在.NET中你很遗忘无法锁定*变量*,你只能锁定*对象*. (5认同)
  • @MattGrande如果`instance`总是非null - `lock`的目的是什么? (2认同)