当前位置:首页 > C# > 正文

C#自定义并行集合(从零开始构建线程安全的集合类)

在现代 C# 开发中,C#并发编程 越来越重要。当我们需要在多个线程之间共享数据时,普通的集合(如 List<T>Dictionary<K, V>)并不安全,可能会引发竞态条件、数据不一致等问题。因此,掌握如何实现一个 C#自定义并行集合 是提升程序健壮性和性能的关键技能。

C#自定义并行集合(从零开始构建线程安全的集合类) C#自定义并行集合 线程安全集合 C#并发编程 自定义集合类 第1张

为什么需要自定义并行集合?

虽然 .NET 提供了 ConcurrentQueue<T>ConcurrentBag<T> 等线程安全集合,但它们的功能有限,无法满足所有业务场景。例如:

  • 你可能需要一个支持“唯一性”的并发集合(类似 HashSet 但线程安全)
  • 你可能希望在添加/删除元素时触发事件
  • 你需要对内部结构进行精细控制以优化性能

这时,我们就需要自己动手实现一个 线程安全集合。本文将带你一步步构建一个简单的并发安全列表 —— ConcurrentList<T>

基础思路:使用锁保护内部状态

最简单的方式是使用 lock 关键字来确保同一时间只有一个线程能访问内部数据。我们将基于 List<T> 封装一层,并在每个公共方法中加锁。

第一步:定义 ConcurrentList 类

using System;using System.Collections;using System.Collections.Generic;public class ConcurrentList<T> : IList<T>{    private readonly List<T> _list = new List<T>();    private readonly object _lock = new object();    public int Count    {        get        {            lock (_lock)            {                return _list.Count;            }        }    }    public bool IsReadOnly => false;    public T this[int index]    {        get        {            lock (_lock)            {                return _list[index];            }        }        set        {            lock (_lock)            {                _list[index] = value;            }        }    }}

第二步:实现关键方法

接下来,我们实现 AddRemoveContains 等常用方法,全部加上锁保护:

public void Add(T item){    lock (_lock)    {        _list.Add(item);    }}public bool Remove(T item){    lock (_lock)    {        return _list.Remove(item);    }}public bool Contains(T item){    lock (_lock)    {        return _list.Contains(item);    }}public void Clear(){    lock (_lock)    {        _list.Clear();    }}public void CopyTo(T[] array, int arrayIndex){    lock (_lock)    {        _list.CopyTo(array, arrayIndex);    }}public IEnumerator<T> GetEnumerator(){    // 注意:这里返回的是副本的枚举器,避免在遍历时被修改    T[] snapshot;    lock (_lock)    {        snapshot = _list.ToArray();    }    return ((IEnumerable<T>)snapshot).GetEnumerator();}IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

提示:GetEnumerator 中我们返回了一个快照(snapshot),这是为了防止在 foreach 遍历时其他线程修改集合导致异常。这是实现 自定义集合类 时常见的技巧。

进阶优化:使用 ReaderWriterLockSlim

如果读操作远多于写操作,使用 ReaderWriterLockSlim 可以提高并发性能。它允许多个读线程同时访问,但写操作独占。

private readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();public bool Contains(T item){    _rwLock.EnterReadLock();    try    {        return _list.Contains(item);    }    finally    {        _rwLock.ExitReadLock();    }}public void Add(T item){    _rwLock.EnterWriteLock();    try    {        _list.Add(item);    }    finally    {        _rwLock.ExitWriteLock();    }}

不过要注意资源释放和异常安全,务必使用 try-finally 块。

总结

通过本教程,你已经学会了如何从零开始构建一个 C#自定义并行集合。我们使用了基本的 lock 机制确保 线程安全集合 的行为正确,并介绍了更高级的 ReaderWriterLockSlim 优化方案。

记住,在 C#并发编程 中,没有“万能”的集合。理解底层原理,才能根据业务需求设计出高效、安全的 自定义集合类

建议你在实际项目中先尝试使用 .NET 内置的并发集合;只有在功能不足时,再考虑自定义实现。这样既能保证稳定性,又能提升开发效率。