多线程 - BlockingCollection
BlockingCollection是线程安全的,多个线程可以同时安全地向集合中添加或取出数据。如果集合达到容量上限,生产者线程会阻塞,直到有空间可以添加数据。
如果集合为空,消费者线程会阻塞,直到有数据可用
可以设置最大容量限制,用于控制集合的大小。
内部通过
IProducerConsumerCollection实现,并发访问时无需额外的锁。
csharp
BlockingCollection<T>.Count
BlockingCollection<T>.Add()
BlockingCollection<T>.Take()
BlockingCollection<T>.TryTake(out T item, int millisecondsTimeout)csharp
// 创建一个容量为5的 BlockingCollection
BlockingCollection<int> collection = new BlockingCollection<int>(5);
// 启动生产者线程
Task producer = Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
collection.Add(i); // 添加数据到集合
Console.WriteLine($"Produced: {i}");
Thread.Sleep(100); // 模拟生产延迟
}
collection.CompleteAdding(); // 标记完成添加
});
// 启动消费者线程
Task consumer = Task.Run(() =>
{
while (!collection.IsCompleted)
{
try
{
int item = collection.Take(); // 从集合中取出数据
Console.WriteLine($"Consumed: {item}");
}
catch (InvalidOperationException)
{
// 集合已完成,捕获异常并退出
break;
}
}
});
// 等待任务完成
Task.WaitAll(producer, consumer);
Console.WriteLine("Processing complete.");底层集合
BlockingCollection 可以使用不同的底层集合。常见的底层集合有:
ConcurrentQueue(默认):先进先出(FIFO)。ConcurrentStack:后进先出(LIFO)。ConcurrentBag:无序集合。
使用 ConcurrentStack 作为底层集合
csharp
BlockingCollection<int> collection = new BlockingCollection<int>(new ConcurrentStack<int>());