MSDN文档是这么说的

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

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


当前回答

想象一下,你的办公室有一位技术娴熟的秘书,这是部门的共享资源。偶尔,你会因为有任务而冲向他们,只希望你的另一个同事还没有认领他们。通常你只需要等很短的一段时间。

因为关心就是分享,你的经理决定顾客也可以直接使用秘书。但这有一个副作用:当您为该客户工作时,客户甚至可能会认领它们,并且您还需要他们执行部分任务。死锁发生,因为声明不再是层次结构。如果从一开始就不允许客户索赔,这完全可以避免。

lock(this) is bad as we've seen. An outside object might lock on the object and since you don't control who's using the class, anyone can lock on it... Which is the exact example as described above. Again, the solution is to limit exposure of the object. However, if you have a private, protected or internal class you could already control who is locking on your object, because you're sure that you've written your code yourself. So the message here is: don't expose it as public. Also, ensuring that a lock is used in similar scenario's avoids deadlocks.

与此完全相反的是锁定整个应用领域共享的资源——这是最坏的情况。这就像把你的秘书放在外面,让外面的人去认领一样。结果是彻底的混乱——或者就源代码而言:这是一个坏主意;把它扔掉,重新开始。我们怎么做呢?

正如这里大多数人指出的那样,类型在应用领域是共享的。但是我们可以使用更好的东西:字符串。原因是字符串被池化了。换句话说,如果你有两个字符串在一个应用域中有相同的内容,它们有可能有完全相同的指针。由于指针被用作锁键,基本上你得到的是“为未定义的行为做好准备”的同义词。

类似地,你不应该锁定WCF对象HttpContext。目前,线程。当前,单例(一般)等。避免这一切的最简单方法是什么?private [static] object myLock = new object();

其他回答

你可以建立一个规则,规定一个类可以有锁定'this'或类中代码实例化的任何对象的代码。所以只有不遵循这个模式才会有问题。

如果您想保护自己不受不遵循此模式的代码的影响,那么接受的答案是正确的。但如果遵循这个模式,那就不是问题。

锁的优点是效率高。如果你有一个简单的“值对象”,它只包含一个值。它只是一个包装器,它被实例化了数百万次。通过要求仅为锁定而创建一个私有同步对象,基本上使对象的大小增加了一倍,分配的数量也增加了一倍。当性能很重要时,这是一个优势。

当您不关心分配数量或内存占用时,出于其他答案中指出的原因,避免锁定(这)是可取的。

如果在共享资源上锁定,则this指针上的锁定可能很糟糕。共享资源可以是一个静态变量,也可以是计算机上的一个文件——即在类的所有用户之间共享的一些东西。原因是,每次实例化类时,this指针将包含对内存中某个位置的不同引用。在一个类的实例中锁定这个和在另一个类的实例中锁定这个是不同的。

请检查这段代码,了解我的意思。在控制台应用程序的主程序中添加以下代码:

    static void Main(string[] args)
    {
         TestThreading();
         Console.ReadLine();
    }

    public static void TestThreading()
    {
        Random rand = new Random();
        Thread[] threads = new Thread[10];
        TestLock.balance = 100000;
        for (int i = 0; i < 10; i++)
        {
            TestLock tl = new TestLock();
            Thread t = new Thread(new ThreadStart(tl.WithdrawAmount));
            threads[i] = t;
        }
        for (int i = 0; i < 10; i++)
        {
            threads[i].Start();
        }
        Console.Read();
    }

创建一个如下所示的新类。

 class TestLock
{
    public static int balance { get; set; }
    public static readonly Object myLock = new Object();

    public void Withdraw(int amount)
    {
      // Try both locks to see what I mean
      //             lock (this)
       lock (myLock)
        {
            Random rand = new Random();
            if (balance >= amount)
            {
                Console.WriteLine("Balance before Withdrawal :  " + balance);
                Console.WriteLine("Withdraw        : -" + amount);
                balance = balance - amount;
                Console.WriteLine("Balance after Withdrawal  :  " + balance);
            }
            else
            {
                Console.WriteLine("Can't process your transaction, current balance is :  " + balance + " and you tried to withdraw " + amount);
            }
        }

    }
    public void WithdrawAmount()
    {
        Random rand = new Random();
        Withdraw(rand.Next(1, 100) * 100);
    }
}

这里是一个程序的运行锁定这个。

   Balance before Withdrawal :  100000
    Withdraw        : -5600
    Balance after Withdrawal  :  94400
    Balance before Withdrawal :  100000
    Balance before Withdrawal :  100000
    Withdraw        : -5600
    Balance after Withdrawal  :  88800
    Withdraw        : -5600
    Balance after Withdrawal  :  83200
    Balance before Withdrawal :  83200
    Withdraw        : -9100
    Balance after Withdrawal  :  74100
    Balance before Withdrawal :  74100
    Withdraw        : -9100
    Balance before Withdrawal :  74100
    Withdraw        : -9100
    Balance after Withdrawal  :  55900
    Balance after Withdrawal  :  65000
    Balance before Withdrawal :  55900
    Withdraw        : -9100
    Balance after Withdrawal  :  46800
    Balance before Withdrawal :  46800
    Withdraw        : -2800
    Balance after Withdrawal  :  44000
    Balance before Withdrawal :  44000
    Withdraw        : -2800
    Balance after Withdrawal  :  41200
    Balance before Withdrawal :  44000
    Withdraw        : -2800
    Balance after Withdrawal  :  38400

下面是在myLock上锁定程序的运行。

Balance before Withdrawal :  100000
Withdraw        : -6600
Balance after Withdrawal  :  93400
Balance before Withdrawal :  93400
Withdraw        : -6600
Balance after Withdrawal  :  86800
Balance before Withdrawal :  86800
Withdraw        : -200
Balance after Withdrawal  :  86600
Balance before Withdrawal :  86600
Withdraw        : -8500
Balance after Withdrawal  :  78100
Balance before Withdrawal :  78100
Withdraw        : -8500
Balance after Withdrawal  :  69600
Balance before Withdrawal :  69600
Withdraw        : -8500
Balance after Withdrawal  :  61100
Balance before Withdrawal :  61100
Withdraw        : -2200
Balance after Withdrawal  :  58900
Balance before Withdrawal :  58900
Withdraw        : -2200
Balance after Withdrawal  :  56700
Balance before Withdrawal :  56700
Withdraw        : -2200
Balance after Withdrawal  :  54500
Balance before Withdrawal :  54500
Withdraw        : -500
Balance after Withdrawal  :  54000

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

...同样的论点也适用于这个结构:

lock(typeof(SomeObject))

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

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

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

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