我很好奇两个例子之下的区别。
案例1)通过只读对象锁定
private readonly object key = new object();
private List<int> list = new List<int>;
private void foo()
{
lock(key){
list.add(1);
}
}
case2)按目标对象本身锁定
private List<int> list = new List<int>;
private void foo()
{
lock(list){
list.add(1);
}
}
这两种情况都足够线程安全吗?我想知道垃圾收集器是否会在某个时间更改list
变量的地址(如0x382743 =&gt; 0x576382),以免线程安全失败。
答案 0 :(得分:3)
只要List<T>
在其代码中没有任何lock(this)
语句,这两个函数的行为就会相同。
但是,因为你不总是知道某个对象是否自行锁定而没有查看它的源代码,所以只需锁定一个单独的对象就更安全了。
需要注意的是,从ICollection
继承的类具有SyncRoot
属性,如果要在不使用单独的情况下锁定集合,则该属性明确是您应该锁定的对象对象
private List<int> list = new List<int>;
private void foo()
{
lock(((ICollection)list).SyncRoot){
list.add(1);
}
}
此internally只是做了与您相同的事情,并创建了一个单独的new Object()
来锁定。
答案 1 :(得分:1)
在这两种情况下,foo()都是线程安全的。但是锁定在单独的只读对象(案例1)上是首选,因为
List<T>
的新实例分配给列表可能会导致一些麻烦,例如丢失锁定代码块的原子性)即使垃圾收集器移动您正在锁定的对象,也可确保锁定正常工作。