[特殊字符] .NET 并发编程利器详解
🧵 .NET 并发编程利器详解
附:volatile 与 Interlocked 在并发控制中的关键作用
📌 引言:为什么需要并发集合?
在多线程编程中,我们经常需要多个线程安全地共享数据 —— 比如生产者消费者模型、任务队列、缓存字典、限流控制等。如果使用普通集合(如 List<T>、Queue<T>、Dictionary<TKey, TValue>),在并发读写时极易引发:
- ❌ 数据竞争(Race Condition)
- ❌ 集合内部结构损坏(如哈希表 rehash 时被多线程修改)
- ❌ 程序崩溃或数据不一致
.NET 提供了 System.Collections.Concurrent 命名空间下的线程安全集合类,专为高并发场景设计,无需手动加锁即可安全使用。
本文将深入讲解:
- ✅
ConcurrentQueue<T>、ConcurrentStack<T>、ConcurrentDictionary<TKey, TValue> - ✅
BlockingCollection<T>与它们的关系 - ✅
SemaphoreSlim如何控制并发度 - ✅
volatile与Interlocked在并发编程中的关键作用 - ✅ 实战示例 + 最佳实践
🧩 一、三大基础并发集合
1. ConcurrentQueue<T> —— 线程安全的先进先出队列
特点:
- FIFO(First In, First Out)
- 无锁或细粒度锁实现,高性能
- 支持多生产者多消费者
常用方法:
Enqueue(T item)— 入队TryDequeue(out T result)— 出队(线程安全)IsEmpty— 是否为空(注意:可能瞬时不准,仅作参考)
示例:
var queue = new ConcurrentQueue<int>();// 生产者线程
Task.Run(() =>
{for (int i = 1; i <= 5; i++){queue.Enqueue(i);Console.WriteLine($"生产: {i}");Thread.Sleep(100);}
});// 消费者线程
Task.Run(() =>
{while (true){if (queue.TryDequeue(out var item)){Console.WriteLine($"消费: {item}");}else if (queue.IsEmpty) break;// 注意:此处可能有竞态,仅演示Thread.Sleep(50);}
});Thread.Sleep(2000);
✅ 适用场景:任务队列、消息缓冲、日志收集等
2. ConcurrentStack<T> —— 线程安全的后进先出栈
特点:
- LIFO(Last In, First Out)
- 同样支持多生产者多消费者
常用方法:
Push(T item)— 压栈TryPop(out T result)— 弹栈
示例:
var stack = new ConcurrentStack<int>();Task.Run(() => {for (int i = 1; i <= 3; i++) {stack.Push(i);Console.WriteLine($"压栈: {i}");}
}