UML
文章图片
时间轮算法
文章图片
时间轮是一种高效、低延迟的调度数据结构。
其在Linux内核中广泛使用,是Linux内核定时器的实现方法和基础之一。
按使用场景,大致可以分为两种时间轮:原始时间轮和分层时间轮。
分层时间轮是原始时间轮的升级版本,来应对时间“槽”数量比较大的情况,对内存和精度都有很高要求的情况。
延迟任务的场景一般只需要用到原始时间轮就可以。
constructor
public HashedWheelTimer(
ThreadFactory threadFactory, //定时任务都是后台任务,需要开启线程,我们通常会通过自定义 threadFactory 来命名线程,嫌麻烦就使用 Executors.defaultThreadFactory()
long tickDuration, //一格的时间长度,默认100ms
TimeUnit unit, //一格的时间长度,默认100ms
int ticksPerWheel, //一圈有多少格,默认 512
boolean leakDetection,//用于追踪内存泄漏
long maxPendingTimeouts//最大允许等待的 Timeout 实例数,也就是我们可以设置不允许太多的任务等待。如果未执行任务数达到阈值,那么再次提交任务会抛出 RejectedExecutionException 异常。默认不限制
) {}
原理分析
文章图片
1、HashedWheelTimer本质上是一个Timer,用于将任务定时执行,newTimeout用于添加任务,stop用于终止Timer执行。
2、HashedWheelTimeout封装了待执行的任务TimerTask,并记录属于哪个时间轮,被添加到哪个bucket上,以及前后节点信息,并提供了任务取消、删除和超时执行的能力。
3、Worker封装了线程执行任务的能力。
4、HashedWheelBucket维护了存储待执行任务的双向链表,并提供了添加、删除和超时执行任务的能力。
使用场景 时间轮是一个高性能,低消耗的数据结构,它适合用非准实时,延迟的短平快任务,例如心跳检测。在netty和kafka中都有使用。
HashedWheelTimer本质是一种类似延迟任务队列的实现,那么它的特点如上所述,适用于对时效性不高的,可快速执行的,大量这样的“小”任务,能够做到高性能,低消耗。
HashedWheelTimer时间轮是一个高性能,低消耗的数据结构,它适合用非准实时,延迟的短平快任务,比如心跳检测和会话探活,对于可靠性要求比较严格的延迟任务,时间轮目前并不是比较好的解决方案,原因如下:原生时间轮是单机的,在分布式和多实例部署的场景中乏力;宕机重新恢复执行,原生时间轮的存储是Mpsc队列,毫无疑问是内存存储,如果出现宕机或者重启,数据是不可恢复的;对于类似订单超时取消的场景,可以考虑时间轮+zk + db的方式实现,zk做中心化控制,避免超时任务在多节点重复执行,也即是数据去重,db做为延时任务的持久化存储,宕机可恢复。
HashedWheelTimer应用场景大致有:
● 心跳检测(客户端探活)
● 会话、请求是否超时
● 消息延迟推送
● 业务场景超时取消(订单、退款单等)
参考文章 【Java IO—HashedWheelTimer】https://www.bianchengquan.com...
https://www.jianshu.com/p/1eb...
https://www.javadoop.com/post...
推荐阅读
- Docker|docker入门及实际应用
- 分布式|Gateway(三)Spring Cloud Gateway内置各类型Predicate(断言)使用说明
- linux|linux命令详解及软件安装(全)
- java|企业数字化最核心的数据智能,它的价值到底在哪()
- Java|Java面向对象的三大特征之继承
- Java|谈谈java中封装的那点事
- Java|全面理解java中的构造方法以及this关键字的用法(超详细)
- Java|java中抽象类和接口的异同点
- Java|学Java· 从new说对象实例化