假设我在类中有一个列表,将在多线程场景中使用。
public class MyClass
{
List<MyItem> _list= new List<MyItem>();
protected object SyncRoot {
get {
return ((IList)_list).SyncRoot;
}
}
public void Execute1()
{
lock(SyncRoot)
{
foreach(var item in _list) DoSomething(item);
}
}
public void Execute2()
{
Item[] list;
lock(SyncRoot)
{
list=_list.ToArray();
}
for(var i=0;i<list.Length;i++) DoSomething(list[i]);
}
}
方法 Execute1 是以线程安全方式枚举列表的“常规”方式。但是 Execute2 呢?这种方法仍然是线程安全的吗?
答案 0 :(得分:2)
在两种情况下,访问(副本)列表都是线程安全的。但是,MyItem元素当然不会以任何方式同步。
第二种形式看起来有点贵,但是当DoSomething()
正在运行时,它将允许在原始版本上添加/删除。该数组就像一种快照,如果符合您的要求,它可能会很有用。请注意,您也可以使用ToList()
。
答案 1 :(得分:1)
只要_list
的每个其他用法也使用相同的lock
语句进行保护,它就是安全的。您将对列表进行独占访问,复制其内容,然后处理副本(由于作用域,您也可以访问该列表)。乍一看有点浪费,但在某些情况下是合法的做法。