我有一个实现IList接口的静态集合。此集合在整个应用程序中使用,包括添加/删除项目。
由于多线程问题,我想知道我能做些什么来确保列表一次修改一个,例如当1个线程尝试添加项目时,另一个线程当时不应该删除项目。
我想知道lock(this)和lock(privateObject)之间有什么区别?在我的情况下哪一个更好?
谢谢。
答案 0 :(得分:4)
lock(this)
将锁定整个实例,而lock(privateObject)
将仅锁定该特定实例变量。第二个是更好的选择,因为锁定整个实例将阻止其他线程对该对象做任何事情。
来自MSDN:
一般情况下,请避免锁定公开 类型或代码之外的实例 控制。常见的构造锁定 (this),lock(typeof(MyType))和 锁(“myLock”)违反此规定 准则:
锁定(这个)是一个问题,如果 实例可以公开访问。
lock(typeof(MyType))是一个问题,如果 MyType可公开访问。
lock(“myLock”)是一个问题,因为任何问题 使用过程中的其他代码 相同的字符串,将共享相同的锁。
最佳做法是定义私有 要锁定的对象,或私有静态 对象变量保护数据常见 对所有情况。
在这种特殊情况下,集合是静态的,这实际上意味着只有一个实例,但仍然不会改变lock(this)
和lock(privateObject)
的行为方式。
即使在静态集合中使用lock(this)
,您仍然可以锁定整个实例。在这种情况下,只要线程A获得方法Foo()
的锁定,所有其他线程就必须等待对集合执行任何操作。
使用lock(privateObject)
意味着一旦线程A获得方法Foo()
的锁定,所有其他线程就可以执行除Foo()
之外的任何其他操作而无需等待。只有当另一个线程尝试执行方法Foo()
时,它才必须等到线程A完成其Foo()
操作并释放锁定。
答案 1 :(得分:1)
lock
关键字有点令人困惑。 lock
语句中的对象表达式实际上只是用于创建关键部分的识别机制。它不是锁的主题,也不是因为它被声明引用而以任何方式保证对多线程操作是安全的。
因此lock(this)
正在创建由包含当前正在执行的方法的类标识的关键部分,而lock(privateObject)
由对象(可能是无论如何)私有的类标识。前者风险更大,因为类的调用者可能无意中使用使用该类实例作为锁定对象的lock
语句来定义自己的关键部分。这可能会导致无意识的线程问题,包括但不限于死锁和瓶颈。
您提到您关注的是同时修改集合的多个线程。我应该指出,即使他们没有修改它,你也应该同样关注读取集合的线程。您可能需要一些相同的安全防护装置来保护读取过程中的集合,就像在写入期间一样。
答案 2 :(得分:1)
将私有成员添加到方法锁定的类中。
例如
public class MyClass : IList
{
private object syncRoot = new object();
public void Add(object value)
{
lock(this.syncRoot)
{
// Add code here
}
}
public void Remove(object value)
{
lock(this.syncRoot)
{
// Remove code here
}
}
}
这将确保在线程之间同步访问列表以添加和删除案例,同时保持对列表的访问。这仍然允许枚举器访问列表,而另一个线程可以修改它,但这会打开另一个问题,如果在枚举期间修改了集合,枚举器将抛出异常。