欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > 多层时间轮实现延迟消息

多层时间轮实现延迟消息

2025/2/22 2:11:20 来源:https://blog.csdn.net/u013978512/article/details/142534665  浏览:    关键词:多层时间轮实现延迟消息

单层时间轮的弊端

对于单层时间轮来说,如果要拉长延迟的时间,要么增加时间轮中槽的数量,要么增大前进指针的时间间隔。但是这两种方式都有弊端

  1. 增加槽的数量:占用内存较高
  2. 增大前进指针的时间间隔:延迟时间不精确
    为了解决上面的问题,我们采用钟表中的秒针、分针、时针一样,通过多层时间轮来挂载延迟任务,这样就可以用少量的内存实现超长的延迟时间。

多层时间轮的结构

时间槽:每个时间轮包含若干时间槽,每个槽代表一个时间片段。
时间轮:多层时间轮通常包含多个时间轮,每一层的精度和范围不同。例如,第一层(细粒度)可以管理毫秒级任务,第二层(中等粒度)可以管理秒级任务,第三层(粗粒度)可以管理分钟级任务。
指针:每个时间轮都有一个指针,用于指向当前时间槽,随着时间的推移指针向前移动。
任务链表:每个时间槽中包含一个任务链表,用于存储定时任务。

代码实战

任务

public class TimerTask implements Runnable{private long delayTime;private Runnable task;public TimerTask(long delayTime, Runnable task) {this.delayTime = delayTime;this.task = task;}public long getDelayTime() {return delayTime;}public Runnable getTask() {return task;}@Overridepublic void run() {task.run();}
}

时间轮

public class TimeWheel {private int slots;private long interval;private int currentSlot = 0;private List<List<TimerTask>> wheel = new ArrayList<>();public TimeWheel(int slots, long interval) {this.slots = slots;this.interval = interval;for (int i = 0; i < slots; i++) {wheel.add(new ArrayList<>());}}public int getCurrentSlot() {return currentSlot;}/**** @param task*/public void addTask(TimerTask task) {//计算置放槽位long delayTime = task.getDelayTime() > interval * slots ? task.getDelayTime() - interval * slots : task.getDelayTime();int slot = (int) ((delayTime / interval) + currentSlot) % slots;//添加任务wheel.get(slot).add(task);}public List<TimerTask> advance() {//前进一个槽位currentSlot = (currentSlot + 1) % slots;//取任务List<TimerTask> tasks = new ArrayList<>(wheel.get(currentSlot));wheel.get(currentSlot).clear();return tasks;}
}

多层时间轮

public class MultiLevelTimeWheel {TimeWheel smallWheel = new TimeWheel(100, 100);//100个槽,每个槽间隔100msTimeWheel middleWheel = new TimeWheel(10, 10000);//10个槽,每个槽间隔10s(小时间轮的一个周期)TimeWheel largeWheel = new TimeWheel(10, 100000);//10个槽,每个槽间隔100s(中时间轮的一个周期)public void addTask(TimerTask task) {long delayTime = task.getDelayTime();if (delayTime < 10000) {smallWheel.addTask(task);} else if (delayTime < 100000) {middleWheel.addTask(task);} else if (delayTime < 1000000) {largeWheel.addTask(task);} else {System.out.println("不支持这么大的延迟");}}public void advance() {List<TimerTask> tasks = smallWheel.advance();for (TimerTask task : tasks) {task.run();}//小时间轮转一圈,需要让中时间轮前进一格,并将对应的任务下放至小时间轮的零刻度,待小时间轮再转一整圈时处理if (smallWheel.getCurrentSlot() == 0) {List<TimerTask> middleTasks = middleWheel.advance();for (TimerTask middleTask : middleTasks) {smallWheel.addTask(middleTask);}}//中时间轮转一圈,需要让大时间轮前进一格,并将对应的任务下放至中时间轮的零刻度if (smallWheel.getCurrentSlot() == 0 && middleWheel.getCurrentSlot() == 0) {List<TimerTask> largeTasks = largeWheel.advance();for (TimerTask largeTask : largeTasks) {middleWheel.addTask(largeTask);}}}
}

运行

public static void main(String[] args) {long start = System.currentTimeMillis();TimerTask timerTask1 = new TimerTask(3000, () -> System.out.println("延迟毫秒数:" + (System.currentTimeMillis() - start)));TimerTask timerTask2 = new TimerTask(33000, () -> System.out.println("延迟毫秒数:" + (System.currentTimeMillis() - start)));TimerTask timerTask3 = new TimerTask(333000, () -> System.out.println("延迟毫秒数:" + (System.currentTimeMillis() - start)));MultiLevelTimeWheel multiLevelTimeWheel = new MultiLevelTimeWheel();multiLevelTimeWheel.addTask(timerTask1);multiLevelTimeWheel.addTask(timerTask2);multiLevelTimeWheel.addTask(timerTask3);while (true) {try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}multiLevelTimeWheel.advance();}}

这里的代码实现只是一个demo,主要是为了了解其中的思想。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词