You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

锁内返回Linq.Where生成的IEnumerable是否线程安全?调用ToList能否实现?

代码示例
public class Data
{
    public bool Init { get; set; }
    public string Value {get; set; }
}

public class Example
{

    private Object myObject = new Object();
    private List<Data> myList = new List<Data>
    {
       new Data { Init = true, Value = "abc" },
       new Data { Init = false, Value = "def" },
    };

    public IEnumerable<string> Get()
    {
        lock(this.myObject)
        {
            return this.myList.Where(i => i.Init == true).Select(i => i.Value);
        }
    }

    public void Set(string value)
    {
        lock (this.myObject)
        {
            this.myList.Add(new Data { Init = false, Value = value });
        }
    }
}
问题解答

问题1:当多个线程调用Get()方法时,该方法是否具备线程安全性?

不具备线程安全性。原因是Get()返回的是Linq延迟执行的IEnumerable<string>,锁仅在创建查询表达式的短暂时间内生效。锁释放后,其他线程(比如调用Set()的线程)可以修改myList。当调用方遍历这个返回的枚举器时,myList可能正在被修改,这会直接抛出InvalidOperationException,或者产生不可预期的遍历结果。

问题2:在上述Linq查询末尾调用.ToList(),能否让Get()方法实现线程安全?

可以实现Get()方法针对myList访问的线程安全。因为.ToList()会在锁的保护下立即完成对myList的遍历,把符合条件的元素复制到一个独立的新List<string>中。锁释放后,即使其他线程修改原myList,也不会影响已经返回的这个副本。调用方遍历返回的列表时,操作的是与原myList无关的独立集合,不会出现并发修改的问题。

需要注意:这种线程安全仅针对myList的集合访问和复制。如果Data对象的Init或Value属性在其他线程被修改,依然会存在线程安全风险——但当前代码中Set()方法只添加新的Data对象,并未修改已有对象的属性,因此在当前场景下是安全的。


内容的提问来源于stack exchange,提问作者NirMH

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 08:47:20