在java中想要使一些任务能够定时地执行,可以有以下几种方法。
1,使用java.util包的Timer和TimerTask类,这是比较简单的方法。写一个类继承TimerTask,覆盖run()方法,并在方法里面加入定时的任务,然后调用Timer对象的schedule(TimerTask task, long delay, long period)方法即可。具体的代码:
importjava.util.Timer;importjava.util.TimerTask;public classDemo extendsTimerTask{
@Overridepublic voidrun() {
//这里添加你需要定时执行的任务
System.out.println("timertask run!");}
public static voidmain(String[] args) {
Timer timer = newTimer();longdelay = 5000;//指定从当前时间延迟多久后开始执行定时的任务,单位是毫秒longperiod = 1000;//指定每次执行任务的间隔时间,单位是毫秒timer.schedule(new Demo(),delay,period);}
}
使用Timer的问题是如果添加了多个定时任务,那么所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务。
2,使用java.util.concurrent.ScheduledExecutorService的scheduleWithFixedDelay或scheduleAtFixedRate方法。首先要写一个类实现runnable或callable接口,覆盖run()或call()方法,在方法里添加你要定时执行的任务。然后创建一个ScheduledExecutorService,调用定时方法。具体的实现如下:
importjava.util.concurrent.Executors;importjava.util.concurrent.ScheduledExecutorService;importjava.util.concurrent.TimeUnit;public classScheduledExecutorDemo implementsRunnable{
@Overridepublic voidrun() {
//这里添加你需要定时执行的任务
System.out.println("scheduled executor run!");}
public static voidmain(String[] args) {
//使用Excutors的静态方法创建一个线程池ScheduledExecutorService,数字代表线程池的大小。
//如果任务数量超过了这个数字,那么任务会在一个queue里等待执行
ScheduledExecutorService service = Executors.newScheduledThreadPool(5);longdelay = 5;//指定从当前时间延迟多久后开始执行定时的任务,时间单位可以在调用方法时指定longperiod = 1;//指定每次执行任务的时间间隔service.scheduleAtFixedRate(newScheduledExecutorDemo(),delay,period,TimeUnit.SECONDS);service.scheduleWithFixedDelay(newScheduledExecutorDemo(),delay,period,TimeUnit.SECONDS);}
}
scheduleAtFixedRate和scheduleWithFixedDelay区别在于:前者是每次执行任务都是在上一个任务开始之后固定的period间隔后开始,而后者则是每次执行任务时都是在上一个任务结束后的period时间后才开始,即后者的任务开始执行的间隔不是固定的,会受到实际任务的执行时间波动。
3,使用ScheduledExecutorService的schedule()方法
上面两种创建定时任务的方法都比较简洁,但是也有一定的缺点,那就是无法在外部控制定时任务的开启和关闭,而且定时的时间也是写死的,不利于后期的维护。所以这里介绍一下第三种方式。我们知道,ScheduledExecutorService类的schedule(Callable call,long delay, TimeUnit unit)方法是让指定的Callable任务call在指定的时间delay延迟后执行,那么我们只要在任务类call的run()方法中使用schedule()方法并传递自身的引用,就可以形成循环调用,让这个任务过一段时间之后重新执行自身。为了解耦,这个任务类还需要有开启和关闭任务、指定延迟时间的接口。详细代码如下:
importjava.util.concurrent.Callable;importjava.util.concurrent.Executors;importjava.util.concurrent.ScheduledExecutorService;importjava.util.concurrent.TimeUnit;
public classMyCallable implementsCallable {
privateScheduledExecutorService scheduledExecutorService= Executors.newScheduledThreadPool(5);private longtimeDelay= 5;
public voidexcute(){
scheduledExecutorService.submit(this);}
public voidstop(){
scheduledExecutorService.shutdown();}
public voidsetTimeDelay(longtimeDelay){
this.timeDelay= timeDelay;}
@OverridepublicObject call() throwsException {
//一些业务逻辑,也就是你要循环执行的代码
System.out.println("my call Executed!");scheduledExecutorService.schedule(this,timeDelay,TimeUnit.SECONDS);return"Called!";}
}
执行这个循环任务的简单示例如下:
public static voidmain(String[] args) throwsException{
MyCallable call = newMyCallable();call.setTimeDelay(1);//指定定时执行的时间间隔call.excute();//执行任务Thread.sleep(10000);//让主线程等待一定时间call.stop();//关闭任务}