我有一个私有静态字段,用于同步(锁定)。现在我有两个函数,我不想同时执行。所以我这样做了:
public class Synchronization
{
private static object _lock = new object();
public void MethodA()
{
lock (_lock)
{
Console.WriteLine("I shouldn't execute with MethodB");
}
}
public void MethodB()
{
lock (_lock)
{
Console.WriteLine("I shouldn't execute with MethodA");
}
}
}
我知道锁定一个对象会阻止单个函数的并行执行,但如果我在同时运行的不同方法中使用相同的锁对象,那么同样会有效吗?简单地说,put可以让任何其他线程获取锁定在另一个函数中已经锁定的对象上吗?
答案 0 :(得分:5)
一次只有一个线程可以获取锁,因此该状态对于单个锁实例上的所有线程都是独占的。因此,在您的示例中,只有一个方法体可能在任何给定时间执行类Synchronization
的所有实例,因为您的锁是静态的。如果要锁定每个类的实例,请不要将锁定对象标记为静态。
您对同步的假设是正确的。
请注意,您应该将锁定对象readonly
标记为完全防水的解决方案。如代码所示,可以重新分配锁定对象,从而打破锁定语义,例如:
public class Synchronization
{
private static object _lock = new object();
public void MethodA()
{
lock (_lock)
{
Console.WriteLine("I shouldn't execute with MethodB");
}
}
public void MethodB()
{
//This shouldn't be allowed!
_lock = new object();
lock (_lock)
{
Console.WriteLine("I shouldn't execute with MethodA");
}
}
}
锁定对象应标记为readonly
,即:
private static readonly object _lock = new object();
答案 1 :(得分:2)
我相信你正确阅读MSDN上的Lock Statement。
答案 2 :(得分:1)
你正确地做到了。您创建了两个不会同时输入的关键部分。
因此,MethodA和MethodB不会同时处于“活动状态”。此外,只有一个MethodA(和MethodB)同时处于活动状态。
这适用于您创建的所有对象。我的意思是:任何MethodA或MethodB中只有一个线程来自任何对象。如果希望锁仅在一个对象中发生,则可以使_lock对象不是静态的。
答案 3 :(得分:1)
根据作为锁定目标的对象授予锁定,而不是发生lock
语句的方法。因此,在您的情况下,多个线程可能会输入各种方法,但一次只有一个线程可以执行lock
语句中的任何代码。
答案 4 :(得分:1)
首先,_lock
不应该是静态的。或者您希望对象的多个实例彼此锁定自己?其次,您应该在类中只有一个synchronized方法。更重要的是,您应该避免类中同步方法之间的依赖关系。否则,您的方法调用者会冒错误并出现意外行为。
例如,考虑一下这段代码:
class Synchronized
{
object lockObj = new object();
int counter = 100;
public void Decrement()
{
lock (this.lockObj)
{
this.counter--;
}
}
public int IsZero()
{
lock (this.lockObj)
{
return this.counter == 0;
}
}
}
现在用共享的同步实例做什么?
像这样使用
while (!synchronized.IsZero())
{
synchronized.Decrement();
}
现在线程1调用Decrement,计数器变为0并且线程2立即调用Decrement,因为它在Decrement方法中等待锁定,而不是IsZero方法。计数器现在为-1,循环是无限的。
并不是锁定机制编程错误,而是调用者没有很好地使用它。如果你只在Synchronized类上暴露了一个同步方法,你就不会愚弄程序员盲目地相信它是安全的。
它应该是这样的:
class Synchronized
{
object lockObj = new object();
int counter = 100;
public bool IfNotZeroDecrement()
{
lock (this.lockObj)
{
if (this.counter > 0)
this.counter--;
return this.counter > 0;
}
}
}
/// Usage:
while (synchronized.IfZeroDecrement())
{
}