简介:
TimeTask是要执行的任务,Timer则是调度器
查看源码则能发现,TimerTask实现的Runnable接口,每次创建一个TimeTask就是创建了一个线程,再使用Timer来启动这个线程,控制这个任务什么时候执行,多久执行一次等。
任务调度
延迟调度
TimerTasktimerTask=newTimerTask() {
@Override
publicvoidrun() {
System.out.println("延迟调度");
}
};
Timertimer=newTimer();
timer.schedule(timerTask,2000);
这个便是启动后2s,调用TimeTask,延迟时间作为schedule的第二个参数传入进去,单位是毫秒,这个是只会调用一次
TimerTasktimerTask=newTimerTask() {
@Override
publicvoidrun() {
System.out.println(Thread.currentThread().getName()+":"+"延迟多次调度");
}
};
Timertimer=newTimer();
timer.schedule(timerTask,2000,1000);
而这个是启动后2s调用,之后每1s再次调用,第二个参数未延迟时间,第三个则为每隔多少时间再次调用,单位都是毫秒,这个可以调用多次。
指定时间调度
TimerTasktimerTask=newTimerTask() {
@Override
publicvoidrun() {
System.out.println(Thread.currentThread().getName()+":"+"指定时间调度");
}
};
Timertimer=newTimer();
longtime=System.currentTimeMillis()+5000;
Datedate=newDate(time);
timer.schedule(timerTask,date);
这个用法和上面延迟调度的用法基本类似,只是第二个参数为调度时间,到了指定的时间自动调度,若时间为过去时间, 则该任务会马上执行,并且不执行之前的任务,这个也是只执行一次,同样,在schedule的第三个参数,也是调用间隔。
TimerTasktimerTask=newTimerTask() {
@Override
publicvoidrun() {
choose++;
System.out.println(Thread.currentThread().getName()+":"+System.currentTimeMillis()+"延迟多次调度"+choose);
}
};
Timertimer=newTimer();
longtimeMillis=System.currentTimeMillis()-5000;
timer.scheduleAtFixedRate(timerTask,newDate(timeMillis),1000L);
执行调度任可以使用scheduleAtFixedRate和schedule两种方法,如果指定的时间为过去时间,那scheduleAtFixedRate则会将之前的任务一起执行,而schedule不会这样,但都是会立即执行。上面的运行结果则是一目了然,前面一张是使用的是scheduleAtFixedRate,在17:38:46运行调用任务时,一次运行了多个,将之前的任务也运行了,而第二张图却没有运行之前的任务。
任务精确性
TimerTasktimerTask=newTimerTask() {
@Override
publicvoidrun() {
try {
System.out.println("start");
Thread.sleep(5000L);
System.out.println(Thread.currentThread().getName()+":"+DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).format(ZonedDateTime.now())+"调度完成");
} catch (InterruptedExceptione) {
e.printStackTrace();
}
}
};
Timertimer=newTimer();
timer.schedule(timerTask,1000L,2000L);
从上面的运行结果可以看出,这个时候输出的结果并不是很准确,在上方,我们设置的是2s进行一次调用,但当我们在执行任务的时候,需要的时间超过了2s,那么,频率则不是所设置的时间,这样,就会导致所产生的结果和所预期的结果有误差。
ExecutorServiceexecutorService=Executors.newCachedThreadPool();
TimerTasktimerTask=newTimerTask() {
@Override
publicvoidrun() {
executorService.execute(newRunnable() {
@Override
publicvoidrun() {
try {
System.out.println("start"+newDate());
Thread.sleep(5000L);
} catch (InterruptedExceptione) {
e.printStackTrace();
}
}
});
}
};
Timertimer=newTimer();
timer.schedule(timerTask,1000L,2000L);
这个时候就需要在执行的任务中,在开一个异步线程,这样就避免了,当调度这个任务之后,还需要等待任务完成才能进行下一次调度,从结果中看,这个时候已经是没2s进行一次任务调度,就和所期望的结果是一样的呢。
关闭任务
privatestaticintchoose=0;
publicstaticvoidmain(String[] args) {
TimerTasktimerTask=newTimerTask() {
@Override
publicvoidrun() {
choose++;
System.out.println(Thread.currentThread().getName()+":"+"延迟多次调度"+choose);
}
};
Timertimer=newTimer();
timer.scheduleAtFixedRate(timerTask,2000L,500L);
stop(timer);
}
publicstaticvoidstop(Timertimer){
if (choose>8){
timer.cancel();
} else {
try {
Thread.sleep(1000);
stop(timer);
} catch (InterruptedExceptione) {
e.printStackTrace();
}
}
}
当我们在开启调度任务后,可能在某种条件下需要关闭调度任务,就可以使用cancel方法,上面这段代码就是当choose大于八时,关闭调度任务,由于在下面那个递归中使用线程睡眠,可能主线程在睡眠时,调度任务执行了多次,使得choose并不是刚到九时就关闭,这里只是做一个演示。