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

C#中lock语句工作机制及多线程读写同步疑问

多线程下lock机制与Dictionary线程安全问题解答
public class Test 
{
    public Test instance = null;
    public static readonly object lockA = new object();
    public static readonly object lockB = new object();
    public Dictionary<string, string> data = new Dictionary<string, string>();

    public static Test Instance 
    {
        get 
        {
            if(instance == null)
            {
                lock(lockA)
                {
                    instance = new Test();
                }
            }
            
            return instance;
        }
    }
    
    
    public async Task Init()
    {
        // fetch and populate data to the "data" dictionary
    }
    
    
    public string Get(string key)
    {
        if(data.ContainsKey(key))
        {
            return data[key];
        }
        else
        {
            return key;
        }
    }
    
    
    public void Update(string key, string value)
    {
        lock(lockB)
        {
            // some other code lines...

            data.Add(key, value); 
        }
    }
}

核心问题解答

  1. 线程B、C、D无需等待lockB释放即可执行Get方法
    Get方法中没有使用lock(lockB)的代码块,所以不管lockB是否被线程A占用,其他线程都能直接进入Get执行读取操作,不会被阻塞。

  2. 你对lock的理解完全正确
    lock语句的作用仅限于阻止其他线程进入使用同一锁对象的lock代码块。只有当其他线程也尝试执行lock(lockB) { ... }这类代码时,才会被阻塞,直到持有锁的线程释放lockB。如果线程执行的代码不涉及同一锁对象的lock块,就不会受到任何限制。

关键风险提示

需要特别注意:.NET的Dictionary<TKey, TValue>本身不是线程安全的。当线程A在lockB块内修改data(比如Add操作)的同时,其他线程在Get中读取data,可能引发以下问题:

  • 读取到不完整的更新数据;
  • 抛出InvalidOperationException(即使是ContainsKey或索引器访问也存在风险)。

如果要实现真正的线程安全,有两种常见方案:

  • 在Get方法中也添加lock(lockB),让读写操作都通过同一锁同步,避免并发冲突;
  • 替换为ConcurrentDictionary<TKey, TValue>,这是专门为多线程场景设计的集合,无需手动加锁就能保证基本的线程安全。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 09:13:14