C#中的静态列表赋值是原子的

根据这个 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在评论中指出,问题可能是关于给定的赋值是否是原子的 – 引用的单个赋值(即单个写入)保证是原子的,但这不会使这个代码安全,因为它是这里不仅仅是一项任务.

点赞