根据此reference assignment is atomic so why is Interlocked.Exchange(ref Object, Object) needed?参考分配保证在所有.NET平台上都是原子的。这段代码是原子的,
public static List<MyType> _items;
public static List<MyType> Items
{
get
{
if (_items== null)
{
_items= JsonConvert.DeserializeObject<List<MyType>>(ConfigurationManager.AppSettings["Items"]);
}
return _items;
}
}
我知道可能有多个对象给定here。但是它会是原子的(我的意思是它将是null或List而不是中间)?
答案 0 :(得分:2)
不,这段代码不是原子的 - 如果从多个线程并行访问Items
,_items
实际上可能会多次创建,不同的调用者可能会收到不同的值。
此代码需要锁定,因为它首先执行读取,分支和写入(在昂贵的反序列化调用之后)。读取和写入本身是原子的,但是 - 没有锁定 - 没有什么可以防止系统切换到读取和写入之间的另一个线程。
在伪(ish)代码中,可能会发生这种情况:
if (_items==null)
// Thread may be interrupted here.
{
// Thread may be interrupted inside this call in many places,
// so another thread may enter the body of the if() and
// call this same function again.
var s = ConfigurationManager.AppSettings.get_Item("Items");
// Thread may be interrupted inside this call in many places,
// so another thread may enter the body of the if() and
// call this same function again.
var i = JsonConvert.DeserializeObject(s);
// Thread may be interrupted here.
_items = i;
}
// Thread may be interrupted here.
return (_items);
这表明,如果没有锁定,多个呼叫者可以获得Items
列表的不同实例。
您应该考虑使用Lazy<T>
,这将使这种初始化变得更加简单和安全。
此外,请注意List<T>
本身不线程安全 - 您可能希望使用其他类型(例如ConcurrentDictionary<T1, T2>
或ReadOnlyCollection<T>
)或者您可能需要使用所有操作锁定此列表。
Rob在评论中指出,问题可能是关于给定的赋值是否是原子的 - 参考的单个赋值(即单个写入)保证是原子的但是不能这段代码是安全的,因为这里不止一个任务。