.NET 中的线程安全数据结构
在多线程编程中,线程安全的数据结构是确保数据一致性和避免竞争条件的关键。.NET 提供了多种线程安全的数据结构,适用于不同的场景,本篇将介绍它们的简单使用以及在 .NET Core 和 .NET Framework 中的可用性。
1. ConcurrentQueue
ConcurrentQueue 是一个线程安全的先进先出 (FIFO) 队列。它允许多个线程同时进行入队和出队操作,而不会导致数据不一致。
使用场景
- 适用于生产者-消费者模式
- 需要保证元素按添加顺序处理的场景
优点
- 高效的并发操作
- 无需显式锁定
示例代码
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;
可用性
- .NET Framework 4.0 及以上
- .NET Core 1.0 及以上
2. ConcurrentStack
ConcurrentStack 是一个线程安全的后进先出 (LIFO) 堆栈。它允许多个线程同时进行入栈和出栈操作。
使用场景
- 适用于需要后进先出处理的场景
- 适用于深度优先搜索算法
优点
- 高效的并发操作
- 无需显式锁定
示例代码
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;
可用性
- .NET Framework 4.0 及以上
- .NET Core 1.0 及以上
3. ConcurrentBag
ConcurrentBag 是一个线程安全的无序集合,适用于频繁添加和删除元素的场景。
使用场景
- 适用于需要频繁添加和删除元素的场景
- 适用于不关心元素顺序的场景
优点
- 高效的并发操作
- 无需显式锁定
示例代码
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;
可用性
- .NET Framework 4.0 及以上
- .NET Core 1.0 及以上
4. ConcurrentDictionary<TKey, TValue>
ConcurrentDictionary<TKey, TValue> 是一个线程安全的键值对集合,类似于 Dictionary<TKey, TValue>。
使用场景
- 适用于需要频繁读取和写入键值对的场景
- 适用于需要线程安全的字典操作的场景
优点
- 高效的并发操作
- 支持原子操作,如
AddOrUpdate和GetOrAdd`
示例代码
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);
可用性
- .NET Framework 4.0 及以上
- .NET Core 1.0 及以上
5. BlockingCollection
BlockingCollection 提供线程安全的添加和移除操作,并支持阻塞和限界功能。可以与ConcurrentQueue<T>, ConcurrentStack<T>, ConcurrentBag<T>等一起使用。
使用场景
- 适用于生产者-消费者模式
- 需要阻塞和限界功能的场景
优点
- 支持阻塞操作
- 支持限界功能
示例代码
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);
可用性
*.NET Framework 4.0 及以上
- .NET Core 1.0 及以上
6. ImmutableList
ImmutableList 是线程安全的,因为所有修改操作都会返回一个新的集合实例。
使用场景
- 适用于需要线程安全且不希望集合被修改的场景
- 适用于需要快照功能的场景
优点
- 天然线程安全
- 不可变性保证数据一致性
示例代码
var list = ImmutableList.Create(1, 2, 3);
var newList = list.Add(4);
Console.WriteLine(string.Join(", ", newList)); // 输出 1, 2, 3, 4
可用性
- .NET Framework 4.5 及以上(需要安装
System.Collections.ImmutableNuGet 包) - .NET Core 1.0 及以上(需要安装
System.Collections.ImmutableNuGet 包)
7. SynchronizedCollection
SynchronizedCollection 是一个线程安全的集合,适用于需要同步访问的场景。
使用场景
- 适用于需要同步访问集合的场景
- 适用于需要线程安全的集合操作的场景
优点
- 内置同步机制
- 线程安全的集合操作
示例代码
var collection = new SynchronizedCollection<int>();
collection.Add(1);
collection.Add(2);
foreach (var item in collection)
{
Console.WriteLine(item); // 输出 1 和 2
}
可用性
- .NET Framework 3.5 及以上
- .NET Core 1.0 及以上
8. SynchronizedReadOnlyCollection
SynchronizedReadOnlyCollection 是一个线程安全的只
读集合。
使用场景
- 适用于需要线程安全的只读集合的场景
- 适用于需要同步访问集合的场景
优点
- 内置同步机制
- 线程安全的只读集合操作
示例代码
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
}
可用性
- .NET Framework 3.0 及以上
- .NET Core 1.0 及以上
9. SynchronizedKeyedCollection<K, T>
SynchronizedKeyedCollection<K, T> 是一个线程安全的键控集合。
使用场景
- 适用于需要线程安全的键控集合的场景
- 适用于需要同步访问集合的场景
优点
- 内置同步机制
- 线程安全的键控集合操作
示例代码
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
}
可用性
- .NET Framework 3.0 及以上
- .NET Core 1.0 及以上
.NET 中的线程安全数据结构的更多相关文章
- Windows API学习---用户方式中的线程同步
前言 当所有的线程在互相之间不需要进行通信的情况下就能够顺利地运行时, Micrsoft Windows的运行性能最好.但是,线程很少能够在所有的时间都独立地进行操作.通常情况下,要生成一些线程来处理 ...
- Tomcat中常见线程说明
http://blog.csdn.NET/jeff_fangji/article/details/41786205 本文讲述了Tomcat的常见线程的功能.名称.线程池和配置等信息,其中源码来自于To ...
- {Python之线程} 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Threading模块 九 锁 十 信号量 十一 事件Event 十二 条件Condition(了解) 十三 定时器
Python之线程 线程 本节目录 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Thr ...
- java 中几种常用数据结构
Java中有几种常用的数据结构,主要分为Collection和map两个主要接口(接口只提供方法,并不提供实现),而程序中最终使用的数据结构是继承自这些接口的数据结构类. 一.几个常用类的区别 1.A ...
- Linux中-POSIX 线程详解
一种支持内存共享的简捷工具 摘自https://www.ibm.com/developerworks/cn/linux/thread/posix_thread1/ 线程是有趣的 了解如何正确运用线 ...
- 每天进步一点点——Linux中的线程局部存储(一)
转载请说明出处:http://blog.csdn.net/cywosp/article/details/26469435 在Linux系统中使用C/C++进行多线程编程时,我们遇到最多的就是对同 ...
- java 中的线程池
1.实现下面的一个需求,控制一个执行函数只能被五个线程访问 package www.weiyuan.test; public class Test { public static void main( ...
- android中的线程池学习笔记
阅读书籍: Android开发艺术探索 Android开发进阶从小工到专家 对线程池原理的简单理解: 创建多个线程并且进行管理,提交的任务会被线程池指派给其中的线程进行执行,通过线程池的统一调度和管理 ...
- rxjava源码中的线程知识
rxjava源码中的线程知识 rx的最精简的总结就是:异步 这里说一下以下的五个类 1.Future2.ConcurrentLinkedQueue3.volatile关键字4.AtomicRefere ...
- C#中的线程(一)入门
文章系参考转载,英文原文网址请参考:http://www.albahari.com/threading/ 作者 Joseph Albahari, 翻译 Swanky Wu 中文翻译作者把原文放在了& ...
随机推荐
- vue 中 slot 的使用方式,以及作用域插槽的用法
分类:插槽又分为匿名插槽.具名插槽以及作用域插槽 : 匿名插槽,我们又可以叫它单个插槽或者默认插槽 因为组件标签中间是不允许写内容的,但是可以插入 插槽 :template 标签 : 插槽的使用方法 ...
- 自签openssl证书(包含泛域名)
1.安装openSSL weget http://www.openssl.org/source/openssl-1.0.0a.tar.gz Tar -zxvf openssl-1.0.0a.tar.g ...
- 09 什么是注意力机制(Attention )
博客配套视频链接: https://space.bilibili.com/383551518?spm_id_from=333.1007.0.0 b 站直接看 配套 github 链接:https:// ...
- 云原生周刊:Gateway API 1.0.0 发布 | 2023.11.6
开源项目推荐 Kueue Kueue 是一套用于作业队列的 API 和控制器.它是作业级管理器,可决定何时允许作业启动(如创建 pod),何时停止作业(如删除活动 pod). Reloader 一个 ...
- Java开发23种设计模式(转)
[转载]https://www.cnblogs.com/maowang1991/archive/2013/04/15/3023236.html 设计模式(Design Patterns) --可复用面 ...
- HTML 中 script 标签的属性和加载顺序
script 标签默认是阻塞加载的,也就是先下载src内容,然后执行src内容,然后再往后读文档 head 中的 script 按顺序加载执行,然后再加载 body 的元素. 把 script 移动到 ...
- 在 Kubernetes 中运行 Locust 与 Selenium:安装 Chrome 和 ChromeDriver
在现代软件开发中,性能和用户体验是至关重要的,而负载测试和自动化测试可以帮助我们实现这一目标.在本文中,我们将讨论如何在 Kubernetes 环境中运行 Locust 和 Selenium,并详细介 ...
- 4年经验来面试20K的测试岗,连基础都不会,还不如招应届生。
公司前段时间缺人,也面了不少测试,结果竟然没有一个合适的.一开始瞄准的就是中级的水准,也没指望来大牛,提供的薪资在10-20k,面试的人很多,但平均水平很让人失望.看简历很多都是3.4年工作经验,但面 ...
- ARC127D Sum of Min of Xor
ARC127D Sum of Min of Xor 性质分析加通用套路. 思路 首先我们把这题的 \(\min\) 给去掉,那么我们按位算贡献,可以求出和.这是这种式子的通用套路. 考虑加上 \(\m ...
- java 子类继承父类 -- 重写、覆盖
class Foo { public int a; public static final String str = "foo"; public Foo() { a = 3; } ...