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); } } }
核心问题解答
线程B、C、D无需等待lockB释放即可执行Get方法
Get方法中没有使用lock(lockB)的代码块,所以不管lockB是否被线程A占用,其他线程都能直接进入Get执行读取操作,不会被阻塞。你对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
相关产品推荐
相关产品推荐

