多级时间轮TimingWheel
一、时间轮是什么
类似现实中的钟表,由多个环形数组组成,每个环形数组包含20个时间单位,表示一个时间维度(一轮),如:第一层时间轮,数组中的每个元素代表1ms,一圈就是20ms,当延迟时间大于20ms时,就“进位”到第二层时间轮,第二层中,每“一格”表示20ms,依此类推…
对于一个延迟任务,大体包含三个过程:进入时间轮、降级和到期执行。
重要属性:
SystemTimer.start() 方法使用一个线程推进时间轮降级。 从DelayQueue delayQueue = new DelayQueue<>(); 取过期的TimerTaskList 数据中过期时间,通过timeWheel.advanceClock(timerTaskList.getExpire()); 方法对TimerTaskList.getExpire()比当前时间轮的currentTime + tickMs 一个时间槽的范围。 通过TimingWheel.overflowWheel 上层时间轮的引用更新当前时间轮的创建时间字段:currentTime。通过timerTaskList.flush(this::addTask);方法执行过期任务(包含降级操作)
TimingWheel 中 private volatile TimingWheel overflowWheel 上层时间轮; 用volatile进行修饰保证数据更新其它线程也可以读取到数据。
TimerTaskList implements Delayed 实现了这个接口,覆写public long getDelay(TimeUnit unit) 和public int compareTo(Delayed o) 方法。
二、hutool 工具包中多级时间轮
- 代码例子
package com.lvyuanj.test.timer;
import cn.hutool.cron.timingwheel.SystemTimer;
import cn.hutool.cron.timingwheel.TimerTask;
/**
-
@author lvyuanjun
-
@date 2023/1/31 11:34
*/
public class TimerTest {public static void main(String[] args) {
SystemTimer systemTimer = new SystemTimer();
TimerTask timerTask = new TimerTask(()->{
System.out.println(“timerTask excute …”);
}, 2000);
systemTimer.start();systemTimer.addTask(timerTask); System.out.println(systemTimer);
}
}
三、为什么要用时间轮
用到延迟任务时,比较直接的想法是DelayQueue、ScheduledThreadPoolExecutor 这些,而时间轮相比之下,最大的优势是在时间复杂度上:
时间复杂度对比:
因此,理论上,当任务较多时,TimingWheel的时间性能优势会更明显