背景
這種定時器也常用,不好奇怎麼實現的嗎?!
參考
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
這理論上是一個延時隊列,本質上是個優先級隊列,按照剩餘時間的多少排序的隊列。
優先級隊列其實是一個堆。
按照堆的算法向上向下挪