当前位置: 首页 > news >正文

线程安全的集合类 ConcurrentQueue、ConcurrentStack、BlockingCollection、ConcurrentBag、ConcurrentDictionary

在 .NET 中,ConcurrentQueue<T>ConcurrentStack<T>ConcurrentBag<T>BlockingCollection<T>ConcurrentDictionary<TKey, TValue> 都是线程安全的集合类,专为多线程并发场景设计,但它们的数据结构、功能特性和适用场景有显著差异。以下是详细对比:
image

核心特性对比表

类型 数据结构 核心功能 线程安全机制 阻塞行为 适用场景 性能特点
ConcurrentQueue<T> 队列(FIFO) 先进先出的线程安全存储 细粒度锁/无锁算法 无阻塞(TryDequeue 立即返回) 多线程生产-消费(顺序处理) 高(入队/出队操作轻量)
ConcurrentStack<T> 栈(LIFO) 后进先出的线程安全存储 细粒度锁/无锁算法 无阻塞(TryPop 立即返回) 多线程生产-消费(逆序处理,如撤销操作) 高(栈操作本身简单)
ConcurrentBag<T> 无序集合 线程本地队列+全局集合的混合存储 线程本地存储+全局锁 无阻塞(TryTake 立即返回) 同一批线程既生产又消费(如线程池任务共享) 极高(优先操作本地队列,减少锁竞争)
BlockingCollection<T> 包装器(默认队列) 对线程安全集合的包装,支持阻塞和容量控制 基于底层集合的同步机制 支持阻塞(Take 等待元素,Add 等待空间) 需要阻塞等待或容量限制的生产-消费 中(额外的阻塞和边界控制逻辑)
ConcurrentDictionary<TKey,TValue> 字典(键值对) 高并发的键值对存储 分段锁(按桶独立加锁) 无阻塞(原子操作) 多线程共享的缓存、计数器、配置表 极高(多线程可同时操作不同键,无锁竞争)

详细说明

1. ConcurrentQueue<T>

  • 数据结构:FIFO(先进先出)队列。
  • 核心操作Enqueue(入队)、TryDequeue(出队,队列空时返回 false)、TryPeek(查看队首元素)。
  • 特点:严格保证元素顺序,适合需要按生产顺序处理的场景。
  • 示例场景:日志收集(多线程写入日志,后台线程按顺序持久化)、任务调度(按提交顺序执行任务)。
var queue = new ConcurrentQueue<int>();
// 多线程入队
queue.Enqueue(1);
queue.Enqueue(2);
// 多线程出队
if (queue.TryDequeue(out int result))
{Console.WriteLine($"出队元素: {result}"); // 必然是1(FIFO)
}

2. ConcurrentStack<T>

  • 数据结构:LIFO(后进先出)栈。
  • 核心操作Push(入栈)、TryPop(出栈,栈空时返回 false)、TryPeek(查看栈顶元素)。
  • 特点:元素按“后入先出”顺序处理,适合需要逆序操作的场景。
  • 示例场景:撤销操作日志(最新操作先撤销)、递归任务的中间结果存储。
var stack = new ConcurrentStack<int>();
// 多线程入栈
stack.Push(1);
stack.Push(2);
// 多线程出栈
if (stack.TryPop(out int result))
{Console.WriteLine($"出栈元素: {result}"); // 必然是2(LIFO)
}

3. ConcurrentBag<T>

  • 数据结构:无序集合(内部为每个线程维护本地队列,减少锁竞争)。
  • 核心操作Add(添加元素)、TryTake(获取并移除任意元素,集合空时返回 false)、TryPeek(查看任意元素)。
  • 特点
    • 无序性:无法保证元素的获取顺序。
    • 高性能:Add 优先加入当前线程的本地队列,TryTake 优先从本地队列获取,几乎无锁竞争。
  • 示例场景:线程池任务共享临时数据(如多线程计算的中间结果)、同一批线程既生产又消费的场景。
var bag = new ConcurrentBag<int>();
// 多线程添加
bag.Add(1);
bag.Add(2);
// 多线程获取(顺序不确定)
if (bag.TryTake(out int result))
{Console.WriteLine($"获取元素: {result}"); // 可能是1或2
}

4. BlockingCollection<T>

  • 数据结构:包装器(默认包装 ConcurrentQueue<T>,也可指定 ConcurrentStack<T>ConcurrentBag<T> 等)。
  • 核心操作
    • Add:添加元素(若设置容量边界,满时阻塞)。
    • Take:获取元素(空时阻塞,直到有元素可用)。
    • CompleteAdding:标记“不再添加元素”,消费者可通过 IsCompleted 判断是否结束。
  • 特点
    • 支持阻塞等待:解决 Concurrent* 集合“空队列时需轮询”的问题。
    • 支持容量限制:防止集合无限增长导致内存溢出。
  • 示例场景
    • 生产者-消费者管道(如下载→解析→存储,每个阶段用 BlockingCollection 衔接)。
    • 需要严格控制并发量的场景(如限制队列最大长度为1000)。
// 容量限制为2的阻塞集合(底层是队列)
var blocking = new BlockingCollection<int>(boundedCapacity: 2);// 生产者(队列满时阻塞)
Task.Run(() => {blocking.Add(1);blocking.Add(2);blocking.Add(3); // 此时队列满,阻塞等待
});// 消费者(队列空时阻塞)
Task.Run(() => {while (!blocking.IsCompleted){int item = blocking.Take(); // 阻塞等待元素Console.WriteLine($"处理元素: {item}");}
});

5. ConcurrentDictionary<TKey, TValue>

  • 数据结构:键值对字典(哈希表实现)。
  • 核心操作
    • 原子操作:GetOrAdd(获取或添加)、AddOrUpdate(添加或更新)、TryRemoveTryUpdate 等。
    • 线程安全的遍历(GetEnumerator 返回快照)。
  • 特点
    • 分段锁设计:将字典分为多个桶,每个桶独立加锁,多线程可同时操作不同键,性能接近单线程操作。
    • 无锁竞争:不同键的操作互不干扰,适合高并发读写场景。
  • 示例场景
    • 缓存系统(多线程读写缓存数据)。
    • 计数器(如记录每个用户的访问次数)。
    • 配置表(多线程读取,偶尔更新)。
var dict = new ConcurrentDictionary<int, string>();
// 原子操作:不存在则添加,存在则返回现有值
var value = dict.GetOrAdd(1, key => $"Value_{key}");// 原子操作:更新或添加
dict.AddOrUpdate(1, key => $"New_Value_{key}", // 键不存在时的逻辑(key, oldValue) => $"{oldValue}_Updated" // 键存在时的逻辑
);

选择建议

  1. 按数据结构选择

    • 需要顺序处理(FIFO)ConcurrentQueue<T>BlockingCollection<T>(默认队列)。
    • 需要逆序处理(LIFO)ConcurrentStack<T>BlockingCollection<T>(指定栈)。
    • 需要无序且高性能ConcurrentBag<T>(同一批线程生产消费)。
    • 需要键值对存储ConcurrentDictionary<TKey, TValue>
  2. 按阻塞需求选择

    • 不需要阻塞(空集合时返回 false) → 直接用 Concurrent* 集合。
    • 需要阻塞等待(空集合时线程暂停)或容量限制 → BlockingCollection<T>
  3. 按性能优先级选择

    • 最高性能(同一批线程操作) → ConcurrentBag<T>
    • 高并发键值对 → ConcurrentDictionary<TKey, TValue>
    • 顺序/逆序操作 → ConcurrentQueue<T>/ConcurrentStack<T>

这些类均无需手动加锁,内部通过优化的同步机制保证线程安全,是多线程编程的首选工具。

http://www.aitangshan.cn/news/155.html

相关文章:

  • 【自学嵌入式:stm32单片机】对射式红外传感器记次
  • Rime-weasel 中州韻輸入法-小狼毫 输入法候选框不显示拼音的解决办法
  • 从美世《中国员工敬业度员工体验白皮书》看AI如何改善员工体验
  • 线程安全的集合类 ConcurrentQueue、BlockingCollection、ConcurrentBag
  • 通达信指标泰乐1号战法指标分享(无偿分享全套指标)
  • 差分约束
  • CMake的简单示例
  • 《乐毅报燕王书》
  • 浅谈C++ const
  • NextJS 02 - 服务端渲染
  • Supervisor安装与使用
  • 假期学习
  • 深入解析:【JavaEE】多线程之Thread类(下)
  • proxmox云镜像安装过程
  • 为什么Moka能留住核心人才?智能继任计划+离职风险预测
  • 文件访问被拒绝。
  • ArcgisPro ArcPy (还未)实现缩放至图层
  • Linux环境 RocketMQ 5.X 三主三从集群部署
  • 从嘉手札2025-8-11
  • android开发将项目升级到target35的解决方法
  • 常见光照范围
  • 无监督训练在NLP中的价值体现
  • HFSS许可证多用户支持
  • 【斯普林格出版、快至见刊后1个月检索】第五届现代教育技术与社会科学国际学术会议(ICMETSS 2025)
  • 8.11
  • 统计出哪个时间段在线人数最多
  • HotSpot虚拟机对象探秘 - Charlie
  • 哨兵卫星 在线查看网站
  • ExpeRepair: Dual-Memory Enhanced LLM-based Repository-Level Program Repair 论文笔记
  • GPT5模型工程重构实践