在多线程编程中,线程安全的数据结构是确保数据一致性和避免竞争条件的关键。.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. kotlin更多语言结构——>操作符重载

    Kotlin允许我们为自己的类型提供预定义的一组操作符的实现.这些操作符具有固定的符号表示(如 + 或 *) 和固定的优先级.为实现这样的操作符,我们为相应的类型(即二元操作符左侧的类型和一元操作符的 ...

  2. 使用 GPU-Operator 与 KubeSphere 简化深度学习训练与 GPU 监控

    本文将从 GPU-Operator 概念介绍.安装部署.深度训练测试应用部署,以及在 KubeSphere 使用自定义监控面板对接 GPU 监控,从原理到实践,逐步浅析介绍与实践 GPU-Operat ...

  3. 高性能 Nginx HTTPS 调优 - 如何为 HTTPS 提速 30%

    为什么要优化 Ngin HTTPS 延迟 Nginx 常作为最常见的服务器,常被用作负载均衡 (Load Balancer).反向代理 (Reverse Proxy),以及网关 (Gateway) 等 ...

  4. vue暗含玄机的v-for指令

    由于是多个事项,那么这个数据模型是一个数组:为了显示这些代办事项我们首先添加一些样本数据 <script> export default { data() { return { title ...

  5. 学习JavaScript第二天

    文章目录 1.运算符(操作符) 1.1运算符的分类 1.2算数运算符 1.3递增和递减运算符 1.4比较运算符 1.5逻辑运算符 2.选择结构 2.1if语句 2.1.1语法 2.1.2案例1:判断闰 ...

  6. 远程连接服务器时出现“这可能是由于CredSSP加密数据库修正”的错误提示的解决办法

    当我们远程连接服务器时,有时候会出现以下提示,从而导致我们无法成功连接服务器,如下所述: 原因: 远程桌面使用的是"凭据安全支持提供程序协议 (CredSSP) ",这个协议在未修 ...

  7. Hadoop未授权访问

    Hadoop未授权访问 是什么? Hadoop 是一种用来处理和存储大量数据的软件工具,可以用来日志分析,推荐系统,数据备份   核心组件: 存储大数据:HDFS 文件系统 处理大数据:MapRedu ...

  8. 5.7 Linux Vim可视化模式

    相信大家都使用过带图形界面的操作系统中的文字编辑器,用户可以使用鼠标来选择要操作的文本,非常方便.在 Vim 编辑器中也有类似的功能,但不是通过鼠标,而是通过键盘来选择要操作的文本. 在 Vim 中, ...

  9. 一文彻底弄懂JUC工具包的Semaphore

    Semaphore 是 Java 并发包 (java.util.concurrent) 中的重要工具,主要用于控制多线程对共享资源的并发访问量.它可以设置"许可证"(permit) ...

  10. 解决MindSpore-2.4-GPU版本的安装问题

    问题背景 虽说在MindSpore-2.3之后的版本中不在正式的发行版中支持GPU硬件后端,但其实在开发分支版本中对GPU后端是有支持的: 但是在安装的过程中可能会遇到一些问题或者报错,这里复现一下我 ...