实用技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > ASP.NET > 实用技巧 > .NET线程安全数据结构

.NET 中的线程安全数据结构详解

作者:贾光辉

.NET提供了多种线程安全的数据结构,适用于不同的场景,本篇将介绍它们的简单使用以及在.NETCore和.NET Framework中的可用性,感兴趣的朋友一起看看吧

在多线程编程中,线程安全的数据结构是确保数据一致性和避免竞争条件的关键。.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;

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;

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;

4. ConcurrentDictionary<TKey, TValue>

ConcurrentDictionary<TKey, TValue> 是一个线程安全的键值对集合,类似于 Dictionary<TKey, TValue>。

适用场景

优点

可用性

示例代码

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

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);

6. ImmutableList

ImmutableList 是线程安全的,因为所有修改操作都会返回一个新的集合实例。

适用场景

优点

可用性

示例代码

var list = ImmutableList.Create(1, 2, 3);
var newList = list.Add(4);
Console.WriteLine(string.Join(", ", newList)); // 输出 1, 2, 3, 4

7. SynchronizedCollection

SynchronizedCollection 是一个线程安全的集合,适用于需要同步访问的场景。

适用场景

优点

可用性

示例代码

var collection = new SynchronizedCollection<int>();
collection.Add(1);
collection.Add(2);
foreach (var item in collection)
{
    Console.WriteLine(item); // 输出 1 和 2
}

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
}

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 中的线程安全数据结构的文章就介绍到这了,更多相关.NET线程安全数据结构内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文