如果任务必须每天准点调度,那就应该使用固定速率调度 , 并且要确保每个任务执行时间不要太长,避免超过period间隔 。
如果任务需要每隔几分钟跑一次,那就使用固定时延调度,它不是很在乎单个任务要跑多长时间 。
我们来模拟一下这个情况 。
首先 , 我们对TimerTask进行修改,让它某一次任务产生大量耗时:
TimerTask task = new TimerTask() {private int i = 1;@Overridepublic void run() {System.out.print(i + " " + DateUtil.formatNow() + " 开始执行, ");if(i == 3) {ThreadUtil.sleep(11 * 1000);}System.out.println(DateUtil.formatNow() + " 结束");i++;}};
该任务在执行第3次时 , 将会休眠11秒 , 这将会导致延误后续的任务 。
2. 固定速率示例:
Timer timer = new Timer("timer");timer.scheduleAtFixedRate(task, 5000, 2000);
设定任务延迟5秒后执行第1次任务 , 之后每2秒执行一次 。
输出:
启动于:2022-10-31 15:51:241 2022-10-31 15:51:29 开始执行, 2022-10-31 15:51:29 结束2 2022-10-31 15:51:31 开始执行, 2022-10-31 15:51:31 结束3 2022-10-31 15:51:33 开始执行, 2022-10-31 15:51:44 结束 *4 2022-10-31 15:51:44 开始执行, 2022-10-31 15:51:44 结束 *5 2022-10-31 15:51:44 开始执行, 2022-10-31 15:51:44 结束 *6 2022-10-31 15:51:44 开始执行, 2022-10-31 15:51:44 结束 *7 2022-10-31 15:51:44 开始执行, 2022-10-31 15:51:44 结束 *8 2022-10-31 15:51:44 开始执行, 2022-10-31 15:51:44 结束 *9 2022-10-31 15:51:45 开始执行, 2022-10-31 15:51:45 结束10 2022-10-31 15:51:47 开始执行, 2022-10-31 15:51:47 结束11 2022-10-31 15:51:49 开始执行, 2022-10-31 15:51:49 结束
如果不存在第3次耗时11秒的情况下,正常任务执行时间应该为:
启动于:2022-10-31 15:51:241 2022-10-31 15:51:29 开始执行, 2022-10-31 15:51:29 结束2 2022-10-31 15:51:31 开始执行, 2022-10-31 15:51:31 结束3 2022-10-31 15:51:33 开始执行, 2022-10-31 15:51:33 结束 *4 2022-10-31 15:51:35 开始执行, 2022-10-31 15:51:35 结束 *5 2022-10-31 15:51:37 开始执行, 2022-10-31 15:51:37 结束 *6 2022-10-31 15:51:39 开始执行, 2022-10-31 15:51:39 结束 *7 2022-10-31 15:51:41 开始执行, 2022-10-31 15:51:41 结束 *8 2022-10-31 15:51:43 开始执行, 2022-10-31 15:51:43 结束 *9 2022-10-31 15:51:45 开始执行, 2022-10-31 15:51:45 结束10 2022-10-31 15:51:47 开始执行, 2022-10-31 15:51:47 结束11 2022-10-31 15:51:49 开始执行, 2022-10-31 15:51:49 结束
但是在第3次执行任务时因为执行耗时11秒,第4次本该在15:51:35开始执行并完成任务 , 却到了15:51:44才执行完成,这11秒延误了后续5个任务的正常执行,因此在15:51:44时,scheduleAtFixedRate赶作业把延误的5个任务一起执行了 。
最后赶上了原本的进度,第9个任务准时在15:51:45执行 。
3. 固定延时示例:
Timer timer = new Timer("timer");timer.schedule(task, 5000, 2000);
输出:
启动于:2022-10-31 15:56:591 2022-10-31 15:57:04 开始执行, 2022-10-31 15:57:04 结束2 2022-10-31 15:57:06 开始执行, 2022-10-31 15:57:06 结束3 2022-10-31 15:57:08 开始执行, 2022-10-31 15:57:19 结束 *4 2022-10-31 15:57:19 开始执行, 2022-10-31 15:57:19 结束5 2022-10-31 15:57:21 开始执行, 2022-10-31 15:57:21 结束6 2022-10-31 15:57:24 开始执行, 2022-10-31 15:57:24 结束7 2022-10-31 15:57:26 开始执行, 2022-10-31 15:57:26 结束8 2022-10-31 15:57:28 开始执行, 2022-10-31 15:57:28 结束9 2022-10-31 15:57:30 开始执行, 2022-10-31 15:57:30 结束10 2022-10-31 15:57:32 开始执行, 2022-10-31 15:57:32 结束
如果不存在第3次耗时11秒的情况下,正常任务执行时间应该为:
启动于:2022-10-31 15:56:591 2022-10-31 15:57:04 开始执行, 2022-10-31 15:57:04 结束2 2022-10-31 15:57:06 开始执行, 2022-10-31 15:57:06 结束3 2022-10-31 15:57:08 开始执行, 2022-10-31 15:57:08 结束 *4 2022-10-31 15:57:10 开始执行, 2022-10-31 15:57:10 结束5 2022-10-31 15:57:12 开始执行, 2022-10-31 15:57:12 结束6 2022-10-31 15:57:14 开始执行, 2022-10-31 15:57:14 结束7 2022-10-31 15:57:16 开始执行, 2022-10-31 15:57:16 结束8 2022-10-31 15:57:18 开始执行, 2022-10-31 15:57:18 结束9 2022-10-31 15:57:20 开始执行, 2022-10-31 15:57:20 结束10 2022-10-31 15:57:22 开始执行, 2022-10-31 15:57:22 结束
使用schedule调度,第4次任务本该在15:57:10开始执行,但由于耗时11秒直到15:57:19才开始 。
而第3次任务实际是在19秒完成, 完成后又在19秒立即执行第4次,中间少了2秒间隔,第4次完成后接着开始2秒一次,变为了从21秒开始执行第5次 。
和我原本的推测不一样的是,本以为19秒完成后,第4次会隔2秒在21秒执行,没想到19秒会立即执行 。
猜测与delay参数有关,但调整了delay后仍然一样 , 完成的那一秒还是会马上再执行第4次任务 。
推荐阅读
- 三 Java多线程-ThreadPool线程池
- 二 Java多线程-线程关键字
- 二 Java 编码那些事
- lol手游戏命师的大招怎么使用(lol手游技能释放技巧)
- 一 Java多线程-线程生命周期
- SpringBoot 常用注解的原理和使用
- 7 Java多线程:JUC(上)
- 一次 Java log4j2 漏洞导致的生产问题
- 眼霜的正确使用顺序,眼霜的正确使用方法
- 漫步者funbuds怎么配对_漫步者funbuds使用说明