首页 > 编程语言 >延时任务-基于netty时间轮算法实现

延时任务-基于netty时间轮算法实现

时间:2022-08-19 13:12:29浏览次数:77  
标签:netty 30 任务 算法 时间 延时 线程

一、时间轮算法简介

为了大家能够理解下文中的代码,我们先来简单了解一下netty时间轮算法的核心原理

时间轮算法名副其实,时间轮就是一个环形的数据结构,类似于表盘,将时间轮分成多个bucket(比如:0-8)。假设每个时间轮轮片的分隔时间段tickDuration=1s(即:指针经过每个格子花费时间是 1 s),当前的时间bucket=3,那么在18秒后需要被执行的任务需要落到((3+18)%8=5取余运算)的5号bucket上。假如有多个需要在该时间段内执行的任务,就会组成一个双向链表。
另外针对时间轮我们要有下面的几个认知:

  • 时间轮指针是一个Worker线程,在时间轮整点的时候执行双向链表中的任务。
  • 时间轮算法的并不是精准的延时,它的执行精度取决于每个时间轮轮片的分隔时间段tickDuration
  • Worker线程是单线程,一个bucket、一个bucket的顺序处理任务。所以我们的延时任务一定要做成异步任务,否则会影响时间轮后续任务的执行时间。

二、时间轮hello-world

实现一个延时任务的例子,需求仍然十分的简单:你买了一张火车票,必须在30分钟之内付款,否则该订单被自动取消。订单30分钟不付款自动取消,这个任务就是一个延时任务。 我们的火车票订单取消任务,从需求上看并不需要非常精准的延时,所以是可以使用时间轮算法来完成这个任务的。

首先通过maven坐标引入netty

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.45.Final</version>
</dependency>

然后我们创建一个时间轮,如果是Spring的开发环境,我们可以这么做。下文中我们new了一个包含512个bucket的时间轮,每个时间轮的轮片时间间隔是100毫秒。

@Bean("hashedWheelTimer")
public HashedWheelTimer hashedWheelTimer(){
    return new HashedWheelTimer(100, TimeUnit.MILLISECONDS, 512);
}

举例:当用户买火车票下单的时候,向时间轮中添加一个30分钟的延时任务。延时任务将在30分钟之后被执行,下文的lambda表达式部分实现了一个TimerTask(task)延时任务。这个延时任务的函数体内,请一定使用异步任务,即:单独起一个线程或者使用SpringBoot异步任务线程池。因为Worker线程是单线程的,你的任务处理时间长于tickDuration会妨碍后续时间轮轮片上的任务的执行。

//订单下单操作
void order(String orderInfo) {
  //下单的时候,向时间轮中添加一个30分钟的延时任务
  hashedWheelTimer.newTimeout(task -> {
    //注意这里使用异步任务线程池或者开启线程进行订单取消任务的处理
    cancelOrder(orderInfo);
  }, 30, TimeUnit.MINUTES);
}

三、异步任务线程池

我们在上文中已经多次强调,时间轮的任务TimerTask的执行内容要做成异步的。最简单的做法就是接到一个任务之后启动一个线程处理该任务。在Spring环境下其实我们有更好的选择,就是使用Spring的线程池,这个线程池是可以自定义的。比如:下文中的用法是我事先定义了一个名字为test的线程池,然后通过@Async使用即可。

@Async("test")
public void cancelOrder(String orderInfo){
  //查询订单支付信息,如果用户未支付,关闭订单
}

可能有的朋友,还不知道该如何自定义一个Spring线程池,可以参考:我之前写过一个SpringBoot的可观测、易配置的线程池开源项目,源代码地址:https://gitee.com/hanxt/zimug-monitor-threadpool 。我的这个zimug-monitor-threadpool开源项目,可以做到对线程池使用情况的监控,我自己平时用的效果还不错,向大家推荐一下!

四、时间轮优缺点

时间轮算法实现延时任务的优点就是,相对于使用JDK的DelayQueue,其算法上具有优势,执行性能相对好一些。
其缺点就是所有的延时任务以及延时触发的管理,都是在单个应用服务的内存中进行的,一旦该应用服务发生故障重启服务,时间轮任务数据将全部丢失。这一缺点和DelayQueue是一样的。为了解决这个问题,我们可以使用redis、RocketMQ等分布式中间件来管理延时任务消息的方式来实现延时任务,这个我会在后续的文章中为大家介绍。
欢迎关注我的公告号:字母哥杂谈,回复003赠送作者专栏《docker修炼之道》的PDF版本,30余篇精品docker文章。字母哥博客:zimug.com

标签:netty,30,任务,算法,时间,延时,线程
From: https://www.cnblogs.com/zimug/p/16601661.html

相关文章

  • 链表反转类算法题
    反转链表类NO1.反转链表给定一个长度为n的链表,反转该链表,输出表头。方法一:迭代法(推荐使用)算法流程:step1:特殊情况判断,空链表或只有一个结点的链表,直接返回头......
  • 算法工程师需要掌握哪些核心技能点?
    一、算法工程师和其他IT从业人员的区别我想大概从事IT行业的开发人员多少对算法岗位都有所了解,但是其实很多人对这个岗位的认知存在一定的误区,或者说是被一些书籍所误导。......
  • 算法--模拟法
      方法:三次翻转(推荐使用)思路:循环右移相当于从第mmm个位置开始,左右两部分视作整体翻转。即abcdefg右移3位efgabcd可以看成AB翻转成BA(这里小写字母看成数组元素,大写......
  • 算法---二分
      classSolution{public:intfindPeakElement(vector<int>&nums){//writecodehere//题目只需要求一个峰值即可,我门可以利用二......
  • 算法联系---二分查找
       classSolution{public:boolFind(inttarget,vector<vector<int>>array){//因为题目的属性可以知道用右上角的元素判断,如果右上角......
  • python | 算法大神左神(左程云)算法课程 第五节
    TodayNew->python|算法大神左神(左程云)算法课程第五节(第几节我已经搞不清了,随便吧。。)针对b站视频左神算法与数据结构,自己练习对应的python代码相关链接:1️⃣b站视......
  • 粒子滤波 PF(Particle filter)算法
    原文链接粒子滤波器方法通常用于视觉跟踪。从统计角度来看,它是一种顺序蒙特卡罗重要抽样方法,用于根据观测序列估计动态系统的潜状态变量。粒子滤波步骤:初始状态:用大量......
  • 算法提高课 第二章 搜索之DFS
    一、DFS之连通性模型1112.迷宫#include<iostream>#include<cstring>#include<algorithm>usingnamespacestd;constintN=110;intT,n;charg[N][N];in......
  • 回溯算法
    一、回溯1、定义:通过选择不同的岔路口来通往目的地(找到想要的结果)每一步都选择一条路出发,能进则进,不能进则退回上一步(回溯),换一条路再试【回溯很适合使用递归】举例......
  • 完整实现-通过DelayQueue实现延时任务
    实现延时任务有很多的方法,网上关于延时任务的实现的文章已经不少了。比如:实现延时任务的10种方法等等。但是这些文章基本上都是将方法大概的列举一下,给出部分示例代码,对于......