导读:本期聚焦于小伙伴创作的《C#如何实现一个线程安全的FIFO队列?ConcurrentQueue的使用方法详解》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C#如何实现一个线程安全的FIFO队列?ConcurrentQueue的使用方法详解》有用,将其分享出去将是对创作者最好的鼓励。

在C#多线程开发中,如果需要在多个线程之间传递数据,普通的非线程安全队列如Queue<T>在并发操作时会出现数据错乱、异常抛出等问题,而ConcurrentQueue作为System.Collections.Concurrent命名空间下的线程安全集合,天然支持多线程的入队和出队操作,是实现线程安全FIFO队列的最佳选择。

C#如何实现一个线程安全的FIFO队列?ConcurrentQueue的使用方法详解

ConcurrentQueue的核心特性

ConcurrentQueue的设计目标是提供无锁或者细粒度锁的线程安全操作,它具备以下几个核心特点:

  • 线程安全:所有公开方法都支持多线程并发调用,无需开发者手动添加lock语句
  • FIFO顺序:严格遵循先进先出的规则,先入队的元素会先被取出
  • 不支持随机访问:没有提供按索引获取元素的方法,只能通过出队操作获取头部元素
  • 高效性:内部采用了分段存储等优化设计,在高并发场景下的性能表现优于手动加锁的普通队列

常用方法介绍

ConcurrentQueue提供了几个核心的实例方法,足以满足大部分使用场景:

入队操作:Enqueue

Enqueue方法用于将元素添加到队列的尾部,该方法没有返回值,永远会成功执行入队操作:

using System;
using System.Collections.Concurrent;

class Program
{
    static void Main()
    {
        // 创建ConcurrentQueue实例
        ConcurrentQueue<string> queue = new ConcurrentQueue<string>();
        // 入队操作
        queue.Enqueue("第一个元素");
        queue.Enqueue("第二个元素");
        Console.WriteLine("入队完成");
    }
}

出队操作:TryDequeue

由于队列可能为空,所以ConcurrentQueue没有设计直接出队的方法,而是提供了TryDequeue方法,该方法会尝试取出队列头部的元素,如果成功取出返回true,否则返回false:

using System;
using System.Collections.Concurrent;

class Program
{
    static void Main()
    {
        ConcurrentQueue<int> queue = new ConcurrentQueue<int>();
        queue.Enqueue(10);
        queue.Enqueue(20);
        
        // 尝试出队
        if (queue.TryDequeue(out int result))
        {
            Console.WriteLine($"成功取出元素:{result}");
        }
        else
        {
            Console.WriteLine("队列为空,无法取出元素");
        }
    }
}

查看队头元素:TryPeek

如果只需要查看队列头部的元素,不需要将其移除,可以使用TryPeek方法,该方法同样返回bool值表示操作是否成功:

using System;
using System.Collections.Concurrent;

class Program
{
    static void Main()
    {
        ConcurrentQueue<string> queue = new ConcurrentQueue<string>();
        queue.Enqueue("测试元素");
        
        if (queue.TryPeek(out string peekResult))
        {
            Console.WriteLine($"队头元素为:{peekResult}");
        }
    }
}

其他辅助方法

  • IsEmpty属性:判断队列是否为空,比获取Count属性更高效,适合在判断队列是否有元素时使用
  • Count属性:获取队列中元素的总数量,该属性需要遍历内部所有分段,性能开销相对较高,非必要不建议频繁调用
  • Clear方法:清空队列中的所有元素,该方法从.NET 6版本开始支持,低版本需要遍历出队实现清空

多线程场景下的使用示例

下面通过一个生产者消费者的示例,演示ConcurrentQueue在多线程场景下的正确使用方式,该示例中一个线程负责生产数据入队,另一个线程负责消费数据出队:

using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        ConcurrentQueue<int> dataQueue = new ConcurrentQueue<int>();
        CancellationTokenSource cts = new CancellationTokenSource();
        
        // 生产者任务:每秒生产一个数据
        Task producer = Task.Run(() =>
        {
            int count = 0;
            while (!cts.Token.IsCancellationRequested)
            {
                dataQueue.Enqueue(count);
                Console.WriteLine($"生产者入队:{count}");
                count++;
                Thread.Sleep(1000);
            }
        });
        
        // 消费者任务:不断尝试取出数据
        Task consumer = Task.Run(() =>
        {
            while (!cts.Token.IsCancellationRequested)
            {
                if (dataQueue.TryDequeue(out int data))
                {
                    Console.WriteLine($"消费者出队:{data}");
                }
                else
                {
                    Console.WriteLine("队列为空,等待新数据");
                }
                Thread.Sleep(500);
            }
        });
        
        // 运行10秒后停止
        await Task.Delay(10000);
        cts.Cancel();
        await Task.WhenAll(producer, consumer);
        Console.WriteLine("程序结束");
    }
}

上述示例中,生产者和消费者线程同时操作同一个ConcurrentQueue实例,没有出现任何线程安全问题,也无需手动添加lock语句,充分体现了ConcurrentQueue在多线程场景下的优势。

和普通Queue对比

对比项普通Queue<T>ConcurrentQueue<T>
线程安全不支持,多线程操作会抛出异常或数据错乱原生支持,无需手动加锁
使用场景单线程或外部手动加锁的多线程场景多线程无锁并发操作场景
性能表现单线程下性能更好,多线程加锁后性能下降明显高并发场景下性能更优
空队列出队会抛出InvalidOperationException异常返回false,不会抛出异常

使用注意事项

  • 不要对ConcurrentQueue使用lock语句,它的方法已经是线程安全的,额外加锁反而会降低性能
  • 尽量避免频繁调用Count属性,如果需要判断队列是否有元素,优先使用IsEmpty属性
  • 低版本.NET Framework中没有Clear方法,如果需要清空队列,可以通过循环调用TryDequeue直到队列为空实现
  • ConcurrentQueue的元素出队后不会被自动销毁,需要开发者自行处理元素的生命周期,避免内存泄漏
ConcurrentQueue是C#中实现线程安全FIFO队列的首选方案,正确使用它可以大幅降低多线程数据同步的复杂度,提升代码的稳定性和性能。

C#_ConcurrentQueue线程安全队列FIFO队列多线程编程修改时间:2026-06-21 12:00:37

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。