目录
- 1. ConcurrentQueue
- 2. ConcurrentStack
- 3. ConcurrentBag
- 4. ConcurrentDictionary<TKey, TValue>
- 5. BlockingCollection
- 6. ImmutableList
- 7. SynchronizedCollection
- 8. SynchronizedReadOnlyCollection
- 9. SynchronizedKeyedCollection<K, T>
在多线程编程中,线程安全的数据结构是确保数据一致性和避免竞争条件的关键。.NET 提供了多种线程安全的数据结构,适用于不同的场景,本篇将介绍它们的简单使用以及在 .NET Core 和 .NET Framework 中的可用性。
1. ConcurrentQueue
ConcurrentQueue
使用场景
- 适用于生产者-消费者模式
- 需要保证元素按添加顺序处理的场景
优点
- 高效的并发操作
- 无需显式锁定
可用性
- .NET Framework 4.0 及以上
- .NET Core 1.0 及以上
示例代码
using System.Collections.Concurrent;
var queue = new ConcurrentQueue<int>();
var cts = new CancellationTokenSource();
var token = cts.Token;
// 生产者任务
var producer = Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
queue.Enqueue(i);
Console.WriteLine($"Enqueued {i}");
Thread.Sleep(100); // 模拟生产延迟
}
}, token);
// 消费者任务
var consumer = Task.Run(() =>
{
while (!token.IsCancellationRequested)
{
if (queue.TryDequeue(out int result))
{
Console.WriteLine($"Dequeued {result}");
}
Thread.Sleep(50); // 模拟消费延迟
}
}, token);
await Task.WhenAll(producer);
cts.Cancel(); // 停止消费者任务
await consumer;
2. ConcurrentStack
ConcurrentStack
使用场景
- 适用于需要后进先出处理的场景
- 适用于深度优先搜索算法
优点
- 高效的并发操作
- 无需显式锁定
可用性
- .NET Framework 4.0 及以上
- .NET Core 1.0 及以上
示例代码
using System.Collections.Concurrent;
var stack = new ConcurrentStack<int>();
var cts = new CancellationTokenSource();
var token = cts.Token;
// 生产者任务
var producer = Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
stack.Push(i);
Console.WriteLine($"Pushed {i}");
Thread.Sleep(100); // 模拟生产延迟
}
}, token);
// 消费者任务
var consumer = Task.Run(() =>
{
while (!token.IsCancellationRequested)
{
if (stack.TryPop(out int result))
{
Console.WriteLine($"Popped {result}");
}
Thread.Sleep(50); // 模拟消费延迟
}
}, token);
await Task.WhenAll(producer);
cts.Cancel(); // 停止消费者任务
await consumer;
3. ConcurrentBag
ConcurrentBag
使用场景
- 适用于需要频繁添加和删除元素的场景
- 适用于不关心元素顺序的场景
优点
- 高效的并发操作
- 无需显式锁定
可用性
- .NET Framework 4.0 及以上
- .NET Core 1.0 及以上
示例代码
using System.Collections.Concurrent;
var bag = new ConcurrentBag<int>();
var cts = new CancellationTokenSource();
var token = cts.Token;
// 生产者任务
var producer = Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
bag.Add(i);
Console.WriteLine($"Added {i}");
Thread.Sleep(100); // 模拟生产延迟
}
}, token);
// 消费者任务
var consumer = Task.Run(() =>
{
while (!token.IsCancellationRequested)
{
if (bag.TryTake(out int result))
{
Console.WriteLine($"Took {result}");
}
Thread.Sleep(50); // 模拟消费延迟
}
}, token);
await Task.WhenAll(producer);
cts.Cancel(); // 停止消费者任务
await consumer;
4. ConcurrentDictionary<TKey, TValue>
ConcurrentDictionary<TKey, TValue> 是一个线程安全的键值对集合,类似于 Dictionary<TKey, TValue>。
使用场景
- 适用于需要频繁读取和写入键值对的场景
- 适用于需要线程安全的字典操作的场景
优点
- 高效的并发操作
- 支持原子操作,如
AddOrUpdate和
GetOrAdd`
可用性
- .NET Framework 4.0 及以上
- .NET Core 1.0 及以上
示例代码
using System.Collections.Concurrent;
var dictionary = new ConcurrentDictionary<int, string>();
// 添加元素
var addTask = Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
dictionary.TryAdd(i, $"value{i}");
Console.WriteLine($"Added key {i} with value value{i}");
}
});
// 更新元素
var updateTask = Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
var ii = i;
dictionary.AddOrUpdate(i, $"new_value{i}", (key, oldValue) => $"new_value{ii}");
Console.WriteLine($"Updated key {i} with value new_value{i}");
}
});
// 读取元素
var readTask = Task.Run(() =>
{
foreach (var key in dictionary.Keys)
{
if (dictionary.TryGetValue(key, out string? value))
{
Console.WriteLine($"Key {key} has value {value}");
}
}
});
await Task.WhenAll(addTask, updateTask, readTask);
5. BlockingCollection
BlockingCollectionConcurrentQueue<T>
, ConcurrentStack<T>
, ConcurrentBag<T>
等一起使用。
使用场景
- 适用于生产者-消费者模式
- 需要阻塞和限界功能的场景
优点
- 支持阻塞操作
- 支持限界功能
可用性
- .NET Framework 4.0 及以上
- .NET Core 1.0 及以上
示例代码
using System.Collections.Concurrent;
var collection = new BlockingCollection<int>(boundedCapacity: 5);
var cts = new CancellationTokenSource();
var token = cts.Token;
// 生产者任务
var producer = Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
collection.Add(i);
Console.WriteLine($"Added {i}");
Thread.Sleep(100); // 模拟生产延迟
}
collection.CompleteAdding();
}, token);
// 消费者任务
var consumer = Task.Run(() =>
{
foreach (var item in collection.GetConsumingEnumerable(token))
{
Console.WriteLine($"Consumed {item}");
Thread.Sleep(50); // 模拟消费延迟
}
}, token);
await Task.WhenAll(producer, consumer);
6. ImmutableList
ImmutableList
使用场景
- 适用于需要线程安全且不希望集合被修改的场景
- 适用于需要快照功能的场景
优点
- 天然线程安全
- 不可变性保证数据一致性
可用性
- .NET Framework 4.5 及以上(需要安装
System.Collections.Immutable
NuGet 包) - .NET Core 1.0 及以上(需要安装
System.Collections.Immutable
NuGet 包)
示例代码
var list = ImmutableList.Create(1, 2, 3);
var newList = list.Add(4);
Console.WriteLine(string.Join(", ", newList)); // 输出 1, 2, 3, 4
7. SynchronizedCollection
SynchronizedCollection
使用场景
- 适用于需要同步访问集合的场景
- 适用于需要线程安全的集合操作的场景
优点
- 内置同步机制
- 线程安全的集合操作
可用性
- .NET Framework 3.5 及以上
- .NET Core 1.0 及以上
示例代码
var collection = new SynchronizedCollection<int>();
collection.Add(1);
collection.Add(2);
foreach (var item in collection)
{
Console.WriteLine(item); // 输出 1 和 2
}
8. SynchronizedReadOnlyCollection
SynchronizedReadOnlyCollection
读集合。
使用场景
- 适用于需要线程安全的只读集合的场景
- 适用于需要同步访问集合的场景
优点
- 内置同步机制
- 线程安全的只读集合操作
可用性
- .NET Framework 3.0 及以上
- .NET Core 1.0 及以上
示例代码
var list = new List<int> { 1, 2, 3 };
var readOnlyCollection = new SynchronizedReadOnlyCollection<int>(list);
foreach (var item in readOnlyCollection)
{
Console.WriteLine(item); // 输出 1, 2, 3
}
9. SynchronizedKeyedCollection<K, T>
SynchronizedKeyedCollection<K, T> 是一个线程安全的键控集合。
使用场景
- 适用于需要线程安全的键控集合的场景
- 适用于需要同步访问集合的场景
优点
- 内置同步机制
- 线程安全的键控集合操作
可用性
- .NET Framework 3.0 及以上
- .NET Core 1.0 及以上
示例代码
public class MyItem
{
public int Id { get; set; }
public string Name { get; set; }
}
var collection = new SynchronizedKeyedCollection<int, MyItem>(item => item.Id);
collection.Add(new MyItem { Id = 1, Name = "Item1" });
collection.Add(new MyItem { Id = 2, Name = "Item2" });
foreach (var item in collection)
{
Console.WriteLine(item.Name); // 输出 Item1 和 Item2
}
标签:场景,Task,线程,var,new,NET,数据结构
From: https://www.cnblogs.com/Tangtang1997/p/18629960