网上的解释是这样的:
在项目中有个需求,一个定时器需要按指定间隔的时间,监控哪些表被修改了。但这指定的间隔是可以在系统运行时修改的,因此就需要对定时器重新shceduler。
2.由于定时器只能被shceduler一次,所以当再次调用时,就会抛出该IllegalStateException:Task already scheduled or cancelled.
3.这是因为一个timerTask实例被调度后,它的state将会被置为SCHEDULED(已进入调度队列,还没有被执行),EXECUTED(已经被执行,还没有被取消),CANCELLED(已经被取消)。因此当timer对象在执行shceduler时,会对state进行判断。
我这里出现的原因是因为多个Timer调用了一个TimeTask,且同时运行。
解决方案一:设多个TimeTask来接收不同的Timer
@SpringBootTest
public class TimerTest {
private static int a = 1;
private static int b = 1;
private static int c = 1;
private static int d = 1;
@Test
public static void main(String[] args) throws ParseException {
TimerTask timerTask1 = new TimerTask() {
@Override
public void run() {
System.out.println("第"+a+++"次在时间date,执行定时任务task");
}
};
TimerTask timerTask2 = new TimerTask() {
@Override
public void run() {
System.out.println("第"+b+++"次在delay毫秒延时之后,执行定时任务task");
}
};
TimerTask timerTask3 = new TimerTask() {
@Override
public void run() {
System.out.println("第"+c+++"次在delay毫秒延时之后,执行定时任务task,并且每间隔period毫秒都执行一次");
}
};
TimerTask timerTask4 = new TimerTask() {
@Override
public void run() {
System.out.println("第"+d+++"次在firstTime开始,执行定时任务task,并且每间隔period毫秒都执行一次");
}
};
Date date = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse("2021-7-15 22:54:10");
Date firstTime = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(" 2021-7-15 22:54:00");
long delay = 6000;
long period = 3000;
/**
代码中定义了一个定时任务TestTask,创建了4个定时器,每个timer都使用了schedule的重载方法
timer1是在指定时间date,执行定时任务task。
timer2是在delay毫秒延时之后,执行定时任务task。
timer3是在delay毫秒延时之后,执行定时任务task,并且每间隔period毫秒都执行一次。
timer4是在firstTime开始,执行定时任务task,并且每间隔period毫秒都执行一次。
*/
Timer timer1 = new Timer();
Timer timer2 = new Timer();
Timer timer3 = new Timer();
Timer timer4 = new Timer();
timer1.schedule(timerTask1,date);
timer2.schedule(timerTask2,delay);
timer3.schedule(timerTask3,delay,period);
timer4.schedule(timerTask4,firstTime,period);
}
}
解决方案二:只同时运行一个Timer,将其他注释掉,要用哪个解开哪个。