Netty源码分析专题[2]-消息队列MpscQueue分析
在看Netty源码的时候看到了这个队列,之前都没见过,所以特地写个笔记记录一下
MpscQueue的Mpsc的全称是Multi producer single consumer【多生成者单消费者】,我们先把单消费者单生成者的情况分析清楚,在多生产者的情况下,多了一步抢位置的动作,就是如果多个线程同时要往队列添加数据,需要先抢占一下最后一个位置,这就涉及多线程同步,可以加锁,但是更多的是CAS操作,线程同步问题就不在这介绍了
1、前序
由于消费者消费数据和生产者生成数据其实流程差不多,所以着重分析一下生产数据的过程,在介绍MpscQueue之前,先回顾一下环形队列,假设现在有一个可以装8个元素的环形队列,结构如下【环形队列只是逻辑上的结构,实际内存只是一个线性结构的数组或者链表,我们以数组的形式展现】:
这里假设消费者能及时消费掉数据,不考虑阻塞的情况,假设现在生产者已经生成到数组的末尾也就是7号位置,那么生产者生产的数据该放在什么位置?
因为是环形结构,逻辑上0号位置和7号位置是首尾相接的,所以下一个位置应该就是0号位置,在数学上就是:(已生产的数据-1)%队列大小,所以需要两个变量
- 1)、pindex:生产者生产的数据个数,从0开始,生产一个数据+1
- 2)、offset:元素需要放置位置在数组的对应下标,其数值为pindex%队列大小
优化一下,求余操作在除数是2的整数次幂时可以转化为按位与操作,这也是为什么很多队列或者内存在分配空间时会将传入的大小转换成2的整数次幂后再进行后续操作的原因,以队列大小为8为例,计算结果如下【二进制位值显示低8位】
Pindex | 队列大小 | 余数(offset) | pindex二进制 | (队列大小-1)二进制 | 按位与二进制 | 按位与十进制 |
---|---|---|---|---|---|---|
0 | 8 | 0 | 0x00000000 | 0x00000111 | 0x00000000 | 0 |
1 | 8 | 1 | 0x00000001 | 0x00000111 | 0x00000001 | 1 |
2 | 8 | 2 | 0x00000010 | 0x00000111 | 0x00000010 | 2 |
3 | 8 | 3 | 0x00000011 |