0

0

C# 并发字典ConcurrentDictionary方法 C#如何实现线程安全的字典操作

煙雲

煙雲

发布时间:2026-02-06 05:49:28

|

844人浏览过

|

来源于php中文网

原创

AddOrUpdate 不是原子的,因其先执行工厂函数再插入或更新,多线程下同一 key 可能多次调用工厂函数且仅保留最后一次结果;工厂函数须为纯函数,否则副作用会导致问题。

c# 并发字典concurrentdictionary方法 c#如何实现线程安全的字典操作

ConcurrentDictionary 的 AddOrUpdate 为什么不是原子的?

AddOrUpdate 看似一步到位,实际是「先读再写」:它会先调用 key 对应的 updateValueFactory(或 addValueFactory),再尝试插入或更新。如果多个线程同时触发对同一个 key 的 AddOrUpdate,可能多次执行工厂函数,且最终只保留最后一次写入结果。

这不是 bug,而是设计使然——它不保证工厂函数只执行一次。若工厂逻辑有副作用(如发 HTTP 请求、修改外部状态),就会出问题。

  • 安全用法:工厂函数必须是纯函数(无副作用、幂等)
  • 替代方案:对关键逻辑加锁,或改用 GetOrAdd + 显式 TryUpdate
  • 注意 updateValueFactory 参数是旧值,不是当前线程看到的“最新”值,可能已过期

TryGetValue 和 ContainsKey 在高并发下会返回不一致结果吗?

会。因为 ConcurrentDictionary 不提供跨操作的事务性保证。ContainsKey 返回 true 后,紧接着调用 TryGetValue,仍可能返回 false——中间 key 被其他线程删掉了。

这不是线程不安全,而是「最终一致性」模型的体现:每个方法自身线程安全,但组合使用时无同步语义。

  • 永远不要写 if (dict.ContainsKey(k)) dict.TryGetValue(k, out v)
  • 直接用 TryGetValue 一次完成「查+取」,它比 ContainsKey + 索引器更高效也更可靠
  • ContainsKey 仅适合做存在性探针(比如日志打点、监控),不用于控制流程分支

Clear() 方法在遍历时调用会导致异常吗?

不会抛出 InvalidOperationException,但遍历结果不可靠:Clear() 是立即清空内部桶数组的,而正在执行的 foreachGetEnumerator() 可能仍在读旧结构,导致漏项、重复项,甚至跳过刚插入的项。

析稿Ai写作
析稿Ai写作

科研人的高效工具:AI论文自动生成,十分钟万字,无限大纲规划写作思路。

下载

它不阻塞遍历,也不等待遍历结束——这是性能换一致性的典型取舍。

  • Clear() 后继续遍历,行为未定义,.NET 不承诺任何顺序或完整性
  • 需要强一致性?改用 lock 包裹整个字典操作,或换 Dictionary + 外部锁(牺牲并发度)
  • 若只是想「重置」,考虑新建实例(dict = new ConcurrentDictionary()),比 Clear() 更可预测

和 Dictionary + lock 相比,ConcurrentDictionary 真的更快吗?

取决于访问模式。在读多写少、key 分布均匀的场景下,ConcurrentDictionary 明显更快;但在高频单 key 写入(如计数器)或极短临界区下,粗粒度 lock 可能反而更轻量。

它的分段锁(默认 31 段)减少了争用,但每次操作仍需哈希定位段、加锁、操作、解锁——这些开销在简单场景下未必优于一个 object 锁。

  • 测性能别只看吞吐,关注 lock 的持有时间与竞争率(可用 Monitor.TryEnter 统计等待)
  • ConcurrentDictionaryCount 属性是 O(n),别在循环里反复读它
  • 初始化时指定合理容量(如 new ConcurrentDictionary(64)),避免扩容时的全局重哈希锁
真正麻烦的从来不是「能不能用」,而是「哪条路径没锁住」「哪个假设悄悄失效了」。尤其当多个 ConcurrentDictionary 方法串在一起,或者混用 Keys/Values 集合时,线程安全的边界就很容易滑出去。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

585

2023.08.02

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

794

2023.08.22

counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

198

2023.11.20

php中foreach用法
php中foreach用法

本专题整合了php中foreach用法的相关介绍,阅读专题下面的文章了解更多详细教程。

139

2025.12.04

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

585

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

550

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

153

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

204

2025.08.29

java连接字符串方法汇总
java连接字符串方法汇总

本专题整合了java连接字符串教程合集,阅读专题下面的文章了解更多详细操作。

7

2026.02.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
10分钟--Midjourney创作自己的漫画
10分钟--Midjourney创作自己的漫画

共1课时 | 0.1万人学习

Midjourney 关键词系列整合
Midjourney 关键词系列整合

共13课时 | 0.9万人学习

AI绘画教程
AI绘画教程

共2课时 | 0.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号