根据这个 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 而不是在中间)?

最佳答案

不,这段代码不是原子的——如果 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> 这将使这种初始化变得更加简单和安全。

When should I use Lazy<T>?

另外,请记住 List<T> 本身不是线程安全的 - 您可能想要使用不同的类型(如 ConcurrentDictionary<T1, T2>ReadOnlyCollection<T> ),或者您可能需要对针对此列表的所有操作使用锁定。

Rob 在评论中指出,问题可能在于给定的赋值是否是原子的 - 引用的单个赋值(即一次写入)保证是原子的,但这并不能使此代码安全,因为存在这里不止一个任务。

10-07 23:08