Java定时任务,
分享于 点击 45041 次 点评:91
Java定时任务,
源自icp云硬盘项目。当时保存了许多有关Timer和ScheduledExecutorService相关的书签,整理一下,删一删书签。
使用ScheduledExecutorService而不是Timer
原因可以总结为一下几点:
由于ScheduledExecutorService是多线程的,所以它可以避免上述的所有问题。
Timer的schedule和scheduleAtFixedRate
这个部分可以参看What is the difference between schedule and scheduleAtFixedRate?。
翻译过来就是:
假设你期望周期5s,每个任务执行2s,那么有如下一个任务:
TTWWWTTWWWTTWWWTT //T=task,W=wait,每个字母代表执行1s
经测试,这时无论使用schedule还是scheduleAtFixedRate都是相同结果。
假设在执行任务过程中发生了GC,以G代表,那么以schedule方法执行如下:
TTWWWGGTTWWWTTWWWTT //G=GC
以scheduleAtFixedRate执行如下:
TTWWWGGTTWTTWWWTT //G=GC
可以看到,在第三次执行的时候W减少了,目的是为了追赶上(catch up)预期的执行时间。如果GC时间比较久的话,那么scheduleAtFixedRate会记录多个需要catch up的任务。
public class Test {
public static long start;
public static void main(String[] args) {
start=System.currentTimeMillis();
TimerTask task1=new TimerTask() {
@Override
public void run() {
System.out.println("任务1开始执行:"+(System.currentTimeMillis()-start)+"-----");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务1结束执行:"+(System.currentTimeMillis()-start));
}
};
TimerTask task2=new TimerTask() {
@Override
public void run() {
System.out.println("任务2开始执行:"+(System.currentTimeMillis()-start)+"-----");
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务2结束执行:"+(System.currentTimeMillis()-start));
}
};
Timer timer=new Timer();
//timer.schedule(task1,0,5000);//A
timer.scheduleAtFixedRate(task1,0,5000);//B
timer.schedule(task2,2000);
//timer.schedule(task2,1000);
}
}
选用注释中A方法的时候,结果如下:
任务1开始执行:4-----
任务1结束执行:2004
任务2开始执行:2004-----
任务2结束执行:6005
任务1开始执行:6005-----
任务1结束执行:8005
任务1开始执行:11005----- //第三次任务
任务1结束执行:13005
任务1开始执行:16006-----
任务1结束执行:18007
选用注释中B方法的时候,结果如下:
任务1开始执行:7-----
任务1结束执行:2015
任务2开始执行:2016-----
任务2结束执行:6017
任务1开始执行:6017-----
任务1结束执行:8017
任务1开始执行:10001----- //第三次任务
任务1结束执行:12002
任务1开始执行:15001-----
任务1结束执行:17001
通过对比可以发现,在执行第二次task1的之前,由于task2的插入,破坏了at fixed rate
这个条件,即按照上次任务开始时间为起点,在第二次执行的时候被Timer记录了
说了这么多废话,其实还是用ScheduledExecutorService作为替代方案更好。
在SpringBoot的环境
使用@scheduled注解即可使用定时任务,而且一定要注意@Async标签的使用,不然一个线程若为死循环,那么下一个定时的任务,到了执行时间依旧不会执行。
参考文章:
- 简单理解java中timer的schedule和scheduleAtFixedRate方法的区别
- What is the difference between schedule and scheduleAtFixedRate?
- Java 并发专题 : Timer的缺陷 用ScheduledExecutorService替代
相关文章
- 暂无相关文章
用户点评