缺点
Java的定时调度可以通过 Timer 和 TimerTask 来实现,但存在以下缺点:
Timer是 单线程运行,即:串行,相互影响。也就是说,对于同一个
Timer里的多个TimerTask任务,如果一个TimerTask任务在执行中,其它TimerTask即使到达执行时间,也只能 排队等待。当
Timer中的一个任务 抛出异常时,会导致其他所有任务 不再执行
阿里开发手册
阿里开发手册 也推荐使用 ScheduledExecutorService
验证第一个缺点
Task1任务类
该类继承 TimerTask 类,实现 run() 方法,该方法中打印 开始时间 和 结束时间,中间注释的部分先不用看
package timerstd;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimerTask;
public class Task1 extends TimerTask {
@Override
public void run() {
String printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
System.out.println("任务1开始时间:" + printTime);
// try {
// System.out.println("休眠5秒");
// Thread.sleep(5000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
System.out.println("任务1结束时间:" + printTime);
}
}
Task2任务类
该类与 Task1 类几乎一样,只是没有中间注释掉的部分
package timerstd;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimerTask;
public class Task2 extends TimerTask {
@Override
public void run() {
String printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
System.out.println("任务2开始时间:" + printTime);
printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
System.out.println("任务2结束时间:" + printTime);
}
}
主启动类
创建一个 Timer 类对象,并立即启动 Task1 和 Task2 任务
注意: 必须是 同一个Timer 类对象,上面介绍缺点时有提到
package timerstd;
import java.util.Timer;
import java.util.TimerTask;
public class TimerTest {
public static void main(String[] args) {
Timer timer = new Timer();
TimerTask tt1 = new Task1();
TimerTask tt2 = new Task2();
// 立即执行
timer.schedule(tt1,0);
timer.schedule(tt2,0);
}
}
执行结果:
任务1开始时间:24-03-07 22-20-29
任务1结束时间:24-03-07 22-20-29
任务2开始时间:24-03-07 22-20-29
任务2结束时间:24-03-07 22-20-29
能够看到两个任务是同一时刻执行的
改造 Task1 类
将注释的部分去掉,延迟 5秒钟,模拟处理业务耗时(处理业务如:查询数据库并处理数据、发邮件、发短信。。。)
package timerstd;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimerTask;
public class Task1 extends TimerTask {
@Override
public void run() {
String printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
System.out.println("任务1开始时间:" + printTime);
try {
System.out.println("休眠5秒");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
System.out.println("任务1结束时间:" + printTime);
}
}
再次运行,执行结果如下:
任务1开始时间:24-03-07 22-22-54
休眠5秒
任务1结束时间:24-03-07 22-22-59
任务2开始时间:24-03-07 22-22-59
任务2结束时间:24-03-07 22-22-59
关键:能够看到,任务1 运行5秒后才结束,导致 任务2 无法立即执行,而是延迟 5秒 才执行
验证缺点2
Task1
该类继承 TimerTask 类,实现 run() 方法,该方法中打印 开始时间 和 结束时间,中间由于 1/0 抛出 运行时异常
package timerstd2;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimerTask;
public class Task1 extends TimerTask {
@Override
public void run() {
String printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
System.out.println("任务1开始时间:" + printTime);
int i = 1/0;
printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
System.out.println("任务1结束时间:" + printTime);
}
}
Task2
该类与 Task1 类几乎一样,只是没有中间 抛异常 的部分
package timerstd2;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimerTask;
public class Task2 extends TimerTask {
@Override
public void run() {
String printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
System.out.println("任务2开始时间:" + printTime);
printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
System.out.println("任务2结束时间:" + printTime);
}
}
主启动类
创建一个 Timer 类对象,并立即启动 Task1 和 Task2 任务
注意: 必须是 同一个Timer 类对象,上面介绍缺点时有提到
package timerstd;
import java.util.Timer;
import java.util.TimerTask;
public class TimerTest {
public static void main(String[] args) {
Timer timer = new Timer();
TimerTask tt1 = new Task1();
TimerTask tt2 = new Task2();
// 立即执行
timer.schedule(tt1,0);
timer.schedule(tt2,0);
}
}
执行结果:
任务1开始时间:24-03-07 23-51-18
Exception in thread "Timer-0" java.lang.ArithmeticException: / by zero
at timerstd2.Task1.run(Task1.java:14)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
由于 Task1 抛异常,导致其他任务都无法执行
解决
将 run() 方法中的代码都用 try catch 处理
Task1
package timerstd2.chuli;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimerTask;
public class Task1 extends TimerTask {
@Override
public void run() {
try {
String printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
System.out.println("任务1开始时间:" + printTime);
int i = 1 / 0;
printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
System.out.println("任务1结束时间:" + printTime);
}catch (Exception e){
e.printStackTrace();
}
}
}
Task2
package timerstd2.chuli;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimerTask;
public class Task2 extends TimerTask {
@Override
public void run() {
try {
String printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
System.out.println("任务2开始时间:" + printTime);
printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
System.out.println("任务2结束时间:" + printTime);
}catch (Exception e){
e.printStackTrace();
}
}
}
再次执行,结果如下:
任务1开始时间:24-03-07 23-55-15
任务2开始时间:24-03-07 23-55-15
任务2结束时间:24-03-07 23-55-15
java.lang.ArithmeticException: / by zero
at timerstd2.chuli.Task1.run(Task1.java:15)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
Task1 执行报错,但 Task2 仍然能正常运行
