前言
在一些简单的时间调度任务时,常用的是Timer和ScheduledThreadPoolExecutor 两种解决方案。在jdk1.5之后,推荐使用ScheduledThreadPoolExecutor。为什么?
缺陷
Timer的缺陷:
1、Timer是单线程。
假如task1是延时1s后执行,task2延时3s后执行,假如task1的执行时间超过了2s,那么task2的延时会超过3s
final long start = System.currentTimeMillis();
TimerTask task1 = new TimerTask() {
@Override
public void run() {
System.out.println("task1 useTime ! " + (System.currentTimeMillis() - start));
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
TimerTask task2 = new TimerTask() {
@Override
public void run() {
System.out.println("task2 useTime ! " + (System.currentTimeMillis() - start));
}
};
Timer timer = new Timer();
timer.schedule(task1, 1000);
timer.schedule(task2, 3000);
看下执行结果
task1 useTime ! 1006
task2 useTime ! 5009
结果可见,当task1的执行时间超过了4s,因此task3是在第1+4秒后执行
2、Timer当执行过程中某个任务出现RuntimeException时,会中断所有任务的执行。
task1抛出RuntimeException,task2周期性执行,也会因为task1的异常而中断。
final TimerTask task1 = new TimerTask()
{
@Override
public void run()
{
throw new RuntimeException();
}
};
final TimerTask task2 = new TimerTask()
{
@Override
public void run()
{
System.out.println("task2 invoked!");
}
};
Timer timer = new Timer();
timer.schedule(task1, 100);
timer.scheduleAtFixedRate(task2, new Date(), 1000);
res:
task2 invoked!
Exception in thread "Timer-0" java.lang.RuntimeException
at com.demo.cxjhihihi.TimerTest$1.run(TimerTest.java:18)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
而当使用线程池时,则不会有这个问题的存在。
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);
final TimerTask task1 = new TimerTask() {
@Override
public void run() {
System.out.println("runtime error");
throw new RuntimeException();
}
};
final TimerTask task2 = new TimerTask() {
@Override
public void run() {
System.out.println("task2 invoked!");
}
};
executorService.schedule(task1, 1, TimeUnit.SECONDS);
executorService.scheduleAtFixedRate(task2, 1, 3, TimeUnit.SECONDS);
res:
runtime error
task2 invoked!
task2 invoked!
task2 invoked!
task2 invoked!
task2 invoked!
task2 invoked!
可见当task1出现异常时,并不影响其余任务的继续执行
3、Timer执行周期任务时依赖系统时间
不知道怎么解释,要不你们使用Timer执行任务时,修改一下系统时间试试。。。很酸爽。ScheduledExecutorService基于时间的延迟,不会由于系统时间的改变发生执行变化。