netty PriorityQueue源码分析

1 netty PriorityQueue简介

netty 的多路复用器的一个典型实现是NioEventLoop,而NioEventLoop的的reactor实现是一个非常高效的模式,可以支持在单线程情况下,完成如下工作,包括:

  1. 读取对端数据发送事件到pipline;
  2. 调动pipline发送数据;
  3. 执行系统调用任务;
  4. 执行定时任务;

这里涉及到的定时任务执行离不开任务加入队列和出队列,而netty正是在AbstractScheduledEventExecutor类中聚合了自己的队列类,本文的主要目的便是介绍一下netty自己实现的这个任务队列,并就相关原理进行分析!

如下图所示是netty实现的优先级队列的继承关系

1573521519826

2 队列结构

首先看看DefaultPriorityQueue的具体结构:

在这里插入图片描述

如上图可知优先级队列含有三个关键要素

  • 大小比较器
  • 负责任务存储的数组–优先级队列实现的堆的结构
  • 堆的大小

通过DefaultPriorityQueue的实例化,我们找到了优先级队列的比较器具体实现,即通过ScheduledFutureTask的compareTo完成任务比较!

在这里插入图片描述

3 ScheduledFutureTask比较的本质

ScheduledFutureTask进行优先级比较的本质,如下图所示,可以推断为当前任务的截止时间,

当截止时间较长者则返回1,如果二者具有相同截止时间则由任务创建时候统一分配的任务id作为唯一标识!

在这里插入图片描述

因为这里的ScheduledFutureTask也是一个个人觉得很有设计感的地方,在此同样给出其相关图示!
在这里插入图片描述

4 优先级队列-入队-堆中插入元素

堆中插入元素的关键就是插入元素与其父节点比较大小,满足条件则维持现状,不满足则进行交换!

下面以队列入队操作分析优先级队列的入队操作,如下所述是队列入队操作offer的基本逻辑,其重点方法为bubbleUp实现,其本质为堆结构的入堆操作!
在这里插入图片描述

这里是入堆操作的具体执行过程,从函数分析可知几个要点:

  1. netty实现的优先级队列是一个小顶堆!
  2. 当插入节点小于父节点值的时候就停止交换.
  3. 当插入节点大于父节点的值的时候就进行交换,然后迭代检查,直到满足步骤二;
    在这里插入图片描述

5 优先级队列-出队-删除堆顶元素

netty的出队过程就是堆的删除键堆顶元素的过程,这里包含两个步骤:

  1. 弹出堆顶元素;
  2. 取最后一个元素自上而下进行堆化操作;

在这里插入图片描述

下图给出的为自上而下堆化过程的完整流程:

在这里插入图片描述

6 本文小结

netty实现优先级队列的本质是利用堆,也就是数组的数据结构,实现队列接口的入队和出队操作接口,具体任务是由自己编写的ScheduledFutureTask任务.这里有如下几点值得我们在以后的编程中借鉴和参考,再次总结如下:

  1. 高效性:使用堆数据结构实现优先级队列–以截止时间长短作为优先级队列的比较凭据,实现一个定时任务执行器----->每次取堆顶元素节点完成任务,代替了每次取整个任务列表执行任务!这样避免了频繁的扫描!
  2. 扩展性: DefaultPriorityQueue实现中中将比较器作为构造函数,提供用户对外定制,这里AbstractScheduledEventExecutor这是基于此定制了自己的比较器,使得优先级队列的复用性更强!
  3. 特别注意ScheduledFutureTask的结构,其使用了queueIndex这个变量来标识在堆中的位置,如果出队了则该索引等于INDEX_NOT_IN_QUEUE;
  4. 编程参考:后续实现定时任务队列处理流程或者实现优先级队列可以参考netty的这种实现,其较为完备的考虑堆化\扩容的相关问题,值得学习和借鉴!

通过再次详细列出其流程主要目的是进一步复习一下堆这种数据结构!

发布了88 篇原创文章 · 获赞 16 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/xinquanv1/article/details/103039942