我正在寻找不使用"这个"在锁中,如果实例是公共可访问的。我尝试下面的例子,我认为不会调用Method1,因为已经在实例的Main方法中获取了锁。但Method1被称为Method2无限期等待。对此的解释将不胜感激。
class Program
{
static void Main(string[] args)
{
Tracker tracker = new Tracker();
lock (tracker)
{
Parallel.Invoke(() => tracker.Method1(),
() => tracker.Method2());
}
}
}
class Tracker
{
private int number = 6;
public void Method1()
{
lock (this)
{
number *= 5;
Console.WriteLine("Method1: " + number);
number /= 4;
Console.WriteLine("Method1: " + number);
}
}
public void Method2()
{
lock (this)
{
number *= 3;
Console.WriteLine("Method2: " + number);
number /= 2;
Console.WriteLine("Method2: " + number);
}
}
}
答案 0 :(得分:6)
不可能锁定一个可公开访问的对象,这只是一个非常糟糕的主意,因为它可以更好地理解对象更多的同步。通常的做法是永远不要锁定在当前类型范围之外可以访问的对象,因为它可以很容易地跟踪可以获取锁的所有可能位置,这使得它更容易诊断同步的潜在问题,并在查看代码时了解正在同步的内容。
当您在公开公开的对象上进行同步时,它将工作,这只是意味着如果遇到问题,您将拥有巨大的空间通过试图弄清楚有问题的相互作用是什么。当非常不同的地方的许多不同代码都与被锁定的对象进行交互时,它也会更容易导致死锁。
答案 1 :(得分:3)
来自Parallel.Invoke
的文档:
并行执行每个提供的操作可能。
所以这就是发生的事情:
Method1
可以重新获取锁定。以下代码打印线程id-s以证明Main
和Method1
在同一个线程中运行。
class Program
{
static void Main(string[] args)
{
Tracker tracker = new Tracker();
Console.WriteLine("Main TID: " + Thread.CurrentThread.ManagedThreadId);
lock (tracker)
{
Console.WriteLine("Main Acquired");
Parallel.Invoke(() => tracker.Method1(),
() => tracker.Method2());
}
}
}
class Tracker
{
private int number = 6;
public void Method1()
{
Console.WriteLine("Method1 TID: " + Thread.CurrentThread.ManagedThreadId);
lock (this)
{
Console.WriteLine("Method1 Acquired");
}
}
public void Method2()
{
Console.WriteLine("Method2 TID: " + Thread.CurrentThread.ManagedThreadId);
lock (this)
{
Console.WriteLine("Method2 Acquired");
}
}
}
输出
Main TID: 1
Main Acquired
Method1 TID: 1
Method1 Acquired
Method2 TID: 3
然后它挂了。 Thread ID
- s显示Method1
与Main
在同一个主题中运行。