背景
这种定时器也常用,不好奇怎么实现的吗?!
参考
https://juejin.im/post/5d63ce9b6fb9a06b28635ecf
demo
先看个demo吧
package com.vava.ecommerse.scheduler;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* @author Steve
* Created on 2020-06
*/
@Component
public class SchedulerDemo {
@Scheduled(cron = "1 * * * * ?")
public void task1(){
System.out.println("test when sec=1");
Thread thread = Thread.currentThread();
System.out.println("ThreadName:" + thread.getName() + ",id:" + thread.getId() + ",group:" + thread.getThreadGroup());
}
@Scheduled(fixedDelay = 5000)
public void task2(){
System.out.println("test fixed delay = 5000");
Thread thread = Thread.currentThread();
System.out.println("ThreadName:" + thread.getName() + ",id:" + thread.getId() + ",group:" + thread.getThreadGroup());
}
}
过程
总体的思路是这样的:
1、在beanpostprocessor中处理注解相关逻辑,将任务注册。
2、applicationListener中触发schedule
3、每个schedule会计算下一次触发的时间,然后扔进去executor中延时执行
4、executor到时间就会执行相应的run方法
执行完指定的任务之后,就会再调用schedule(),回到第3步,再计算下一次的执行时间,然后扔进executor等待执行。
如何实现delay一段时间然后执行呢?
上面我们看到调用this.executor.schedule(this, initialDelay, TimeUnit.MILLISECONDS);
就可以delay一段时间然后执行相应的代码。具体是怎么实现的呢?
这里我们的executor是scheduledThreadPoolExecutor,可以step into看一下
包装了一下成为RunnableScheduledFuture,然后delayedExecute(t),再step into
把任务加到队列中。。
然后就会有地方消费这个队列里的任务才是。。?
参考:https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html
也就是这个:
ScheduledThreadPoolExecutor内部使用一个DelayedWorkQueue
这理论上是一个延时队列,本质上是个优先级队列,按照剩余时间的多少排序的队列。
优先级队列其实是一个堆。
按照堆的算法向上向下挪