首先,基本使用:入队(EnQueue) 、出队(TryDequeue) 、是否为空(IsEmpty)、获取队列内元素数量(Count)。

一、ConcurrentQueue内部结构:

1.实现原理

众所周知,在普通的非线程安全队列有两种实现方式:

1.使用数组实现的循环队列。

2.使用链表实现的队列。

先看看两种方式的优劣:

.Net Farmework中的普通队列Queue的实现使用了第一种方式,缺点是当队列空间不足会进行扩容,扩容的主要实现是开辟一个原始长度2倍的新数组,然后将原始数组里面的数据复制到新数组中,所以当扩容时就会产生不小的内存开销,在并发的环境中对性能的影响不可小视。当然在调用Queue的构造函数时可以指定默认空间的大小,但是一般情况下数据量是不可预测的,选大了会照成空间浪费,选小了会有复制内存的开销,而且队列扩容以后需要显示调用TrimToSize()方法才能回收掉不使用的内存空间。

第二种链表实现方式虽然消除了空间浪费的问题但是又增加了GC的压力,当入队时会分配一个新节点,出队时要对该节点进行废弃,对于大量的出队入队操作时该实现方式性能不高。

综合以上两种实现方式,在支持多线程并发出队并发入队的情况下,ConcurrentQueue使用了分段存储的概念(如上图所示),ConcurrentQueue分配内存时以段(Segment)为单位,一个段内部含有一个默认长度为32的数组和执行下一个段的指针,有个和Head和Tail指针分别指向了起始段和结束段(这种结构有点像操作系统的段式内存管理和页式内存管理策略)。这种分配内存的实现方式不但减轻的GC的压力而且调用者也不用显示的调用TrimToSize()方法回收内存(在某段内存为空时,会由GC来回收该段内存)。

2.Segment(段)内部结构

其实对于ConcurrentQueue的操作其实就是对Segment(数据段)的操作。

Segment可抽象出如下数据结构:

Segment内部主要方法:

Segment内部和用数组实现的普通队列相当,只不过对于入队和出队操作使用了原子操作来防止多线程竞争问题,使用随机退让等技术保证活锁等问题,实现机制和ConcurrentStack差别不大,跟多TryAppend的实现细节在源码注释中已经阐述的非常清楚这里就再做不过多的解释。

二、入队操作

如上图所示,入队操作是在尾部的段中进行,当数据进入段内失败时会先进行一个回退操作然后再不断尝试直到成功,这里失败的原因(tail.Append(item)返回false)只有一个就是当该段内的空间不够时正在分配新的段,这段时间内会进入该段的元素会失败。

三、出队操作

如上图所示,出队失败时返回false 而不是像入队一样进行回退操作,因为出队失败的原因只有一个就是当队列内所有段的元素为空时,所以出队设计成了返回bool值的函数。

四、判断是否为空(IsEmpty)

整个判断为O(1)的复杂度 主要有三种情况:

1. 头节点(段)不为空返回false

2. 头节点为空而且下一个节点也为空返回true

3. 头节点为空而且下一个节点不为空返回false,这种情况说明队列正在扩容,所以要自选等待扩容完毕时再次进行判断

五、获取队列内元素数量(Count)

找到头节点的low的位置和尾节点的high的位置,由于每个段内记录了当前段在队列中的索引,所以很容易求出整个队列中元素的数量。

跟ConcurrentStack一样 微软官方文档和注释中也说明:判断队列是否为空要使用IsEmpty属性而不是判断Count == 0  原因在于GetHeadTailPositions在大量数据入队和出队的过程中寻找头尾节点的位置是比较耗时的操作,要不断循环确定头尾节点的位置,所以判断队列是否为空还是使用IsEmpty属性。

学习线程安全队列ConcurrentQueue相关推荐

  1. 【Python爬虫学习笔记11】Queue线程安全队列和GIL全局解释器锁

    Queue线程安全队列 在Python多线程编程中,虽然threading模块为我们提供了Lock类和Condition类借助锁机制来处理线程并发执行,但在实际开发中使用加锁和释放锁仍是一个经常性的且 ...

  2. 无锁队列 concurrentqueue介绍(转载)

    背景 由于最近在做一个项目,但是框架本身有个不合理的设计.其中的代码是单线程的,数据的读取和计算都在一个线程里面完成.也就是说,我们的程序有很大的一部分时间在读取文件数据,导致最终的运行速度很慢.这里 ...

  3. [一起读源码]走进C#并发队列ConcurrentQueue的内部世界 — .NET Core篇

    在上一篇<走进C#并发队列ConcurrentQueue的内部世界>中解析了Framework下的ConcurrentQueue实现原理,经过抛砖引玉,得到了一众大佬的指点,找到了.NET ...

  4. python 线程安全队列_Python实现线程安全队列

    原标题:Python实现线程安全队列 作者:愤怒的屎壳螂 来源:http://blog.csdn.net/hit0803107/article/details/52876143 最近学习spark,我 ...

  5. 一文弄懂Java线程安全队列

    文章目录 一.分类 二.BlockingQueue 阻塞队列 三.ConcurrentLinkedQueue 非阻塞队列 一.分类 java中所有队列都继承至java.util.Queue接口,该接口 ...

  6. 【C++ 语言】线程安全队列 ( 条件变量 | 线程调度 )

    文章目录 I . 线程简单使用 II . 互斥锁 III . 条件变量 线程同步 IV . 完整代码示例 006_ThreadSafeQueue.h 006_ThreadSafeQueue.cpp S ...

  7. TensorFlowIO操作(一)----线程和队列

    线程和队列 在使用TensorFlow进行异步计算时,队列是一种强大的机制. 为了感受一下队列,让我们来看一个简单的例子.我们先创建一个"先入先出"的队列(FIFOQueue),并 ...

  8. python 测试 多线程 _thread和threading模块 线程同步,线程优先级队列

    文章目录 python 多线程简介 Python中使用线程的两种方式 1.函数式 示例 2.线程模块 示例 线程同步 示例 线程优先级队列( Queue)[暂时没用到,没仔细看] 示例 其他 thre ...

  9. java多线程 --ConcurrentLinkedQueue 非阻塞 线程安全队列

    ConcurrentLinkedQueue是一个基于链接节点的无界线程安全队列,它采用先进先出的规则对节点进行排序,当我们添加一个元素的时候,它会添加到队列的尾部:当我们获取一个元素时,它会返回队列头 ...

最新文章

  1. python做定时任务的方式及优缺点_python BlockingScheduler定时任务及其他方式的实现...
  2. Linux下gedit显示行号
  3. Android左边有固定文字的EditText
  4. 1.20 main()方法
  5. java数组写入excel_求将java中数组内容逐条加进excel中的代码
  6. 跟踪React流–将Spring Cloud Sleuth与Boot 2结合使用
  7. 开启协程_「科普」什么是协程?
  8. 数据的插入、更新、删除
  9. linux内核安装教程,Linux内核5.9的最重要功能及安装方法
  10. 调整地面材质_家用浴室柜台面什么材质好?Pvc和大理石选哪个合适?
  11. 【安装包】eclipse
  12. 中国移动MM7 API用户手册
  13. AI中的图像识别技术的原理及过程
  14. 任务三、学生喂养三种宠物:猫、狗和鸟
  15. vue element 的el-checkbox-group默认全部选中
  16. 128 黙齎 李貴 曷若親征
  17. 工作日志22-04-22
  18. adb连接夜神模拟器和连接夜神多开的方法
  19. 推广链接生成html操作流程,推广链接使用指引
  20. 剑客之剑——君子剑(Notepad++)

热门文章

  1. Url跳转和伪静态html解决方案
  2. 电脑快捷键和电脑磁盘清理
  3. 经纬度与UTM(Universal Transverse Mercator Projector:通用横轴卡墨托投影)的坐标变换代码
  4. 集成学习算法的思想、通过集成学习提高整体泛化能力的前提条件、如何得到独立的分类器Bagging、Boosting、Stacking算法
  5. Linux安装jdk和docker安装jdk
  6. 计算机图形学绪论:感知、光、颜色和数学
  7. TDD和BDD的区别 (TDD vs BDD)
  8. vue.js devtools
  9. 数据库连接池种类、C3P0数据库连接池、德鲁伊数据库连接池
  10. PID控制算法原理通俗讲解