我一直在做错锁吗?

时间:2012-02-23 20:20:49

标签: c# multithreading locking

我正在阅读关于单身人士线程安全的this article,这让我觉得我不理解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对象,而不是锁定要锁定的实际对象?

3 个答案:

答案 0 :(得分:13)

在您有一个要锁定的对象之前,您第一次访问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中复制它是一个坏主意:(

答案 1 :(得分:2)

锁定this或任何其他非私有对象是危险的,因为如果其他人也尝试使用该对象进行同步,则可能导致死锁。

这并不是非常可能,这就是为什么人们可以养成多年没有被咬过的习惯。但它仍然有可能,object的私有实例的成本可能不足以证明风险的存在。

答案 2 :(得分:1)

对于锁定,您可以使用任何类型的对象,类型确实无关紧要,它只是用作标志,并且只有一个线程可以在一段时间内保存它。

当然可以将其作为锁定参数。但我想不推荐的主要原因是某个地方的其他类也可以使用你的类的实例作为锁定对象,这可能会导致存在问题