假设我已执行此类操作:
A.B.C.add(new D());
A.B.add(new C));
A.add(new B));
这些操作同时执行 。想象一下,这些方法有三种不同的方法。
lock(A.B.C)
A.B.C.add(new D());
lock(A.B)
A.B.add(new C));
lock(A)
A.add(new B));
这些锁是否独立?换句话说 - 这些行动是在同一时间执行,还是仅在前一个行动完成后才执行?
如果它是正确的 - 它是设置锁定的最有效方法吗?
修改
我有很多这种类型的调用(这3种方法被多次调用)。
答案 0 :(得分:0)
是的,锁是彼此独立的。 lock
语句实际上在参数实例上创建了一个监视器,它没有考虑到你实际到达那里的方式(即属性链A.B.C
)。
但是,您的代码存在一个微妙的问题。由于锁是独立的,并且三个锁语句可以同时执行,所以任何语句都可以是
lock(A.B.C)
A.B.C.Add(new D());
是危险的,因为当获得锁定时,属性A.B.C可能已经改变。因此,为此使用局部变量会更好(即更安全):
var c = A.B.C;
lock(c)
c.Add(new D());
答案 1 :(得分:0)
这些陈述将同时进行。您可以通过运行以下代码并看到控制台全部立即写入来测试这一点:
Task.Run(() =>
{
lock (a.B.C)
{
Console.WriteLine("a.B.C");
Thread.Sleep(5000);
}
});
Task.Run(() =>
{
lock (a.B)
{
Console.WriteLine("a.B");
Thread.Sleep(5000);
}
});
Task.Run(() =>
{
lock (a)
{
Console.WriteLine("a");
Thread.Sleep(5000);
}
});
来自C# reference:
最佳做法是定义要锁定的私有对象
所以在这种情况下的内容如下:
public class A
{
private readonly object _syncLock = new object();
public B B { get; private set; }
public A()
{
}
public void Add(B b)
{
lock (_syncLock)
{
// The actual logic
}
}
}
这样,线程安全性由Add
方法本身处理,因此不需要考虑外部调用。