跳到主要内容

C# 线程安全集合

在多线程编程中,线程安全是一个非常重要的概念。线程安全意味着多个线程可以同时访问和操作共享资源,而不会导致数据不一致或其他不可预见的错误。C#提供了一些线程安全的集合类,这些类在多线程环境中可以安全地使用。

什么是线程安全集合?

线程安全集合是指在多线程环境中,多个线程可以同时访问和修改集合,而不会导致数据不一致或其他问题。C#中的线程安全集合类位于 System.Collections.Concurrent 命名空间中,这些类提供了线程安全的操作,避免了手动加锁的复杂性。

常见的线程安全集合

C#提供了多种线程安全集合类,以下是其中一些常见的类:

  • ConcurrentQueue<T>:线程安全的先进先出(FIFO)队列。
  • ConcurrentStack<T>:线程安全的后进先出(LIFO)栈。
  • ConcurrentDictionary<TKey, TValue>:线程安全的字典。
  • ConcurrentBag<T>:线程安全的无序集合。

ConcurrentQueue<T>

ConcurrentQueue<T> 是一个线程安全的队列,支持多线程的入队和出队操作。以下是一个简单的示例:

csharp
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;

class Program
{
static void Main()
{
ConcurrentQueue<int> queue = new ConcurrentQueue<int>();

// 启动多个任务并行入队
Parallel.For(0, 10, i =>
{
queue.Enqueue(i);
});

// 启动多个任务并行出队
Parallel.For(0, 10, i =>
{
if (queue.TryDequeue(out int result))
{
Console.WriteLine($"Dequeued: {result}");
}
});
}
}

输出:

Dequeued: 0
Dequeued: 1
Dequeued: 2
Dequeued: 3
Dequeued: 4
Dequeued: 5
Dequeued: 6
Dequeued: 7
Dequeued: 8
Dequeued: 9

ConcurrentDictionary<TKey, TValue>

ConcurrentDictionary<TKey, TValue> 是一个线程安全的字典,支持多线程的添加、删除和更新操作。以下是一个简单的示例:

csharp
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;

class Program
{
static void Main()
{
ConcurrentDictionary<string, int> dict = new ConcurrentDictionary<string, int>();

// 启动多个任务并行添加键值对
Parallel.For(0, 10, i =>
{
dict.TryAdd($"Key{i}", i);
});

// 启动多个任务并行读取键值对
Parallel.For(0, 10, i =>
{
if (dict.TryGetValue($"Key{i}", out int value))
{
Console.WriteLine($"Key{i}: {value}");
}
});
}
}

输出:

Key0: 0
Key1: 1
Key2: 2
Key3: 3
Key4: 4
Key5: 5
Key6: 6
Key7: 7
Key8: 8
Key9: 9

实际应用场景

线程安全集合在多线程编程中有广泛的应用场景。例如,在一个多线程的Web服务器中,可以使用 ConcurrentQueue<T> 来存储待处理的任务,多个工作线程可以从队列中取出任务并处理。这样可以避免任务丢失或重复处理的问题。

另一个常见的应用场景是使用 ConcurrentDictionary<TKey, TValue> 来缓存数据。多个线程可以同时读取和更新缓存,而不需要手动加锁。

总结

线程安全集合是C#多线程编程中的重要工具,它们提供了线程安全的操作,避免了手动加锁的复杂性。通过使用 ConcurrentQueue<T>ConcurrentDictionary<TKey, TValue> 等线程安全集合类,可以更轻松地编写高效且安全的多线程程序。

附加资源与练习

  • 练习1:尝试使用 ConcurrentBag<T> 实现一个多线程的任务分配系统。
  • 练习2:使用 ConcurrentStack<T> 实现一个多线程的撤销操作栈。
  • 参考文档System.Collections.Concurrent Namespace
提示

在使用线程安全集合时,务必理解其内部实现机制,以便在特定场景下选择最合适的集合类。