理论基础
小顶堆
参考 https://blog.csdn.net/zhizhengguan/article/details/106826270
时间轮算法
参考 https://blog.csdn.net/yu757371316/article/details/107320068
分层时间轮
JDK定时器 Timer使用及原理
1、timer的使用
3、timer中存在的问题
4、timer的应用场景分析
package com.wxl.example.timer;import java.util.Date;import java.util.Timer;import java.util.TimerTask;public class TimerTest {public static void main(String[] args) {Timer t = new Timer(); //任务启动for (int i = 0; i<1; i++) {TimerTask timerTask = new FoolTimerTask("task" + i);// t.schedule(timerTask, new Date(),2000); //任务添加 任务执行超时 丢任务t.scheduleAtFixedRate(timerTask, new Date(),2000); //任务添加 丢任务 执行时间混乱//在 run中使用定时任务线程池规避}}}class FoolTimerTask extends TimerTask {private String name;public FoolTimerTask(String name) {this.name = name;}@Overridepublic void run() {try{System.out.println("name=" + name + ",startTime=" + new Date());Thread.sleep(3000);System.out.println("name=" + name + ",endTime=" + new Date());}catch(Exception e){e.printStackTrace();}}}
定时任务线程池解析
1、使用简介
线程池中每个独立任务串行执行,各任务执行并行
可以看到此时虽然我们指定的周期为 2 s,但是因为任务的运行就需要 3 s(超过周期),所以这种情况下 scheduleAtFixedRate 的处理方式为 上一次任务刚完成,则紧接着立即运行下一次任务,而不是使用线程池中的空闲线程来运行任务以维护 2 秒这个周期 —— 由此可见,每个定时任务在 ScheduledThreadPoolExecutor 中,都是串行运行的,即下一次运行任务一定在上一次任务结束之后。
如果某一个线程出现异常则丢弃。
如果定时任务数量超过 初始线程数量,因为小根堆的原因,leader-follower模式。
注意: DelayQueue是无界队列(maximumPoolSize参数无效);DelayQueue内部封装了一个PriorityQueue,它会根据time的先后时间排序,若time相同则根据sequenceNumber排序
参考: https://blog.csdn.net/xueguchen/article/details/117550455
package com.wxl.example.timer;import java.util.Date;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;public class ScheduleThreadPoolTest {public static void main(String[] args) {ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);// Executors.newSingleThreadExecutor();for (int i = 0; i<3; i++) {Runnable task = new Task("task" + i);// scheduledExecutorService.schedule(task, 2L, TimeUnit.SECONDS); //执行一次scheduledExecutorService.scheduleAtFixedRate(task, 0,2, TimeUnit.SECONDS);// 可以看到此时虽然我们指定的周期为 2 s,但是因为任务的运行就需要 3 s(超过周期),// 所以这种情况下 scheduleAtFixedRate 的处理方式为 上一次任务刚完成,则紧接着立即运行下一次任务,// 而不是使用线程池中的空闲线程来运行任务以维护 2 秒这个周期 —— 由此可见,每个定时任务在 ScheduledThreadPoolExecutor 中,// 都是串行运行的,即下一次运行任务一定在上一次任务结束之后。}}}class Task implements Runnable {private String name;public Task(String name) {this.name = name;}@Overridepublic void run() {try{System.out.println("name=" + name + ",startTime=" + new Date());Thread.sleep(3000);System.out.println("name=" + name + ",endTime=" + new Date());}catch(Exception e){e.printStackTrace();}}}
2、Leader-Follower模式

多线程网络模型:
线程会有三种身份中的一种:leader和follower,以及一个干活中的状态:proccesser
基本原则:永远最多只有一个leader,而所有follower都在等待成为leader。
线程池启动时会自动产生一个Leader负责等待网络IO事件,当有一个事件产生时,Leader线程首先通知一个Follower线程将其提拔为新的Leader,然后自己执行这个任务,去处理这个网络事件,处理完毕后加入Follower线程等待队列,等待下次成为Leader。
这种方法可以增强CPU高速缓存相似性,及消除动态内存分配和线程间的数据交换。
3.ScheduledThreadPoolExecutor与Timer的区别
- Timer是单线程模式,ScheduledThreadPoolExecutor是多线程模式,并且重用线程池
- Timer调度是基于操作系统的绝对时间的,ScheduledThreadPoolExecutor调度是基于相对时间的,不受操作系统时间改变的影响
- Timer不会捕获TimerTask抛出的异常,加上Timer又是单线程的。一旦某个调度任务出现异常,则整个线程就会终止,其他需要调度的任务也不再执行。ScheduledThreadPoolExecutor基于线程池来实现调度功能,某个任务抛出异常后,其他任务仍能正常执行。
- Timer中执行的TimerTask任务整体上没有优先级的概念,只是按照系统的绝对时间来执行任务。ScheduledThreadPoolExecutor距离下次执行的时间间隔短的任务的优先级比较高
- Timer不支持对任务的排序。ScheduledThreadPoolExecutor为需要调度的每个任务按照距离下次执行时间间隔的大小来排序
- Timer无法从TimerTask中获取返回的结果。ScheduledThreadPoolExecutor中FutureTask类,能够通过Future来获取返回的结果。
定时任务框架-quartz
1、使用简介
2、各组件介绍
3、组件关系架构分析
4、监听器及插件
5、springboot整合quartz
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId></dependency><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>${quartz.version}</version></dependency><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz-jobs</artifactId><version>${quartz.version}</version></dependency>
@RequestMapping("/test")public void test() {TriggerKey triggerKey = TriggerKey.triggerKey("trigger1", "trigger1");//确保触发器在调度器里是唯一的if (scheduler == null) {System.out.println("注入失败");return;}try {Trigger trigger = scheduler.getTrigger(triggerKey);if (trigger == null) {trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(CronScheduleBuilder.cronSchedule("0/3 * * * * ?")).build();}JobDetail jobDetail = JobBuilder.newJob(QuartzJob.class).withIdentity("job1","job1").usingJobData("name", "测试调度").build();scheduler.scheduleJob(jobDetail,trigger);scheduler.start();} catch (SchedulerException e) {e.printStackTrace();}}
