Skip to content

线程安全类

ConcurrentQueue

ConcurrentQueue 表示线程安全的先进先出正序)的集合(线程安全队列)。

常用属性:

名称作用
Count获取安全队列的元素个数
IsEmpty判断安全队列是否为空,官方建议使用该属性,而不是使用 Count == 0判断
C#
var cq = new ConcurrentQueue<int>();

for (int i = 0; i < 1000; i++)
	cq.Enqueue(i);

// 获取队列长度
int count = cq.Count;

// 判断队列是否为空
bool isEmpty = cq.IsEmpty;

常用方法:

名称作用
Enqueue()将元素追加到队列末尾(入队)
TryDequeue()尝试返回队列的第一个元素,并将其从队列移除(出队)
TryPeek()尝试返回队列的第一个元素,但不将其从队列移除
Clear()清空队列
ToArray()将队列中的元素复制到一个新数组,可用于遍历
Equals()判断给定对象与队列是否相等
GetType()获取队列实例的Type
C#
// 尝试返回队列的第一个元素,并将其移除
cq.TryDequeue(out int result);

// 尝试返回队列的第一个元素,但不将其移除
cq.TryPeek(out int result);

// 将并发队列中的元素复制到一个新数组
foreach (int item in cq.ToArray())
{
    Console.WriteLine(item);
}

// 判断给定对象与队列是否相等
cq.Equals(cq);

// 获取并发队列实例的Type
Type type = cq.GetType();

// 清空队列
cq.Clear();

ConcurrentStack

ConcurrentStack 表示线程安全的后进先出倒序)集合。

常用属性:

名称作用
Count返回集合的元素个数
IsEmpty判断集合是否为空
C#
var stack = new ConcurrentStack<int>();

Action pusher = () =>
{
    for (int i = 0; i < 1000; i++)
			stack.Push(i);
};
pusher();

// 获取集合的元素个数
int count = stack.Count;

// 判断集合是否为空
bool isEmpty = stack.IsEmpty;

常用方法:

名称作用
Push()顶部插入一个元素
TryPop()尝试弹出并返回顶部的对象,会删除该元素
TryPeek()尝试从顶部获取元素,但不删除该元素
PushRange()自动将多个对象插入集合顶部
ToArray()将集合复制到新数组
Clear()移除集合中的所有元素
C#
// 顶部插入一个元素
stack.Push(9999);

// 自动将多个对象插入集合顶部
int[] ints = [1111, 2222, 3333, 4444, 5555];
stack.PushRange(ints);

// 尝试从顶部获取元素,不删除该元素
stack.TryPeek(out int result);

// 尝试获取顶部的对象,删除该元素
stack.TryPop(out int result1);

// 将集合复制到新数组
foreach (int item in stack.ToArray())
{
    Console.WriteLine(item);
}

// 移除集合中的所有元素
stack.Clear();

ConcurrentDictionary

ConcurrentDictionary 表示可由多个线程同时访问的 键/值对 的线程安全集合。

常用属性:

名称作用
Count获取线程安全字典的 键值对 个数
IsEmpty判断线程安全字典是否为空
Item[key]获取或设置 key 对应的值
Keys获取线程安全字典所有 键 的集合
Values获取线程安全字典所有 值 的集合
C#
var cd = new ConcurrentDictionary<int, string>();
cd.TryAdd(1, "王一博");
cd.TryAdd(2, "任嘉伦");

int count = cd.Count;

bool isEmpty = cd.IsEmpty;

string? res = cd[1];

ICollection<int>? keys = cd.Keys;

ICollection<string>? values = cd.Values;

常用方法:

名称作用
TryAdd(key, value)尝试添加键值对到字典
TryGetValue(key, out var value)尝试获取键对应的值
TryRemove(key, out var value)尝试从字典移除值
TryUpdate(key, newVal, comparisonVal)尝试更新值,如果 key 对应的值等于 comparisonVal,则替换值为 newVal
AddOrUpdate()添加或更新值,详见示例
GetOrAdd()获取或添加(如果键不存在,则添加,如果存在,则不添加并返回key对应的值)
ToArray()将原字典复制到新数组中
ContainsKey(key)判断字典是否包含某个键
Clear()清空字典
C#
// 尝试获取键对应的值
cd.TryGetValue(1, out string? name);

// 尝试从字典移除值
cd.TryRemove(1, out string? name);
cd.TryRemove(1, out string? _);

// 尝试更新值(键 1 对应的值是王一博,则更新为蔡徐坤)
cd.TryUpdate(1, "蔡徐坤", "王一博");

// 添加或更新
cd.AddOrUpdate(1, (key) => "sunny", (key, value) => "sunny");
cd.AddOrUpdate(1, _ => "sunny", (_, _) => "sunny");
cd.AddOrUpdate(1, "sunny", (key, value) => "sunny");

// 获取或添加(如果键 1 不存在,则添加其值为 sunny,如果存在,则返回原始值)
string val = cd.GetOrAdd(1, (key) => "sunny");

// 复制到新数组
foreach (var (key,value) in cd.ToArray())
{
    Console.WriteLine($"{key}{value}");
}

// 判断字典是否包含某个键
bool isContain = cd.ContainsKey(1);

// 清空字典
cd.Clear();

ConcurrentBag

ConcurrentBag<T> 是一个线程安全集合类,适用于存储 无序 对象的集合。

它具有以下优势:

  • 线程安全:允许多个线程同时对进行读写操作,无需显式锁定(lock);
  • 高吞吐量:专门设计用于多线程环境,具有较高的吞吐量,适合频繁添加和删除元素的场景;
  • 无序性:它不关心元素存储的顺序,因此效率更高;

常用属性:

属性作用
Count获取集合元素个数

常用方法:

方法作用
Add()向集合添加一个元素
TryTake()尝试从集合中取出元素,并移除元素
TryPeek()尝试从集合中取出元素,但不移除元素
C#
var bag = new ConcurrentBag<int>();
Parallel.For(0, 100, bag.Add);

var count = bag.Count;

while (bag.TryTake(out int item))
{
  Console.WriteLine(item);
}

Released under the MIT License.