JAVA定时调度Timer类和TimerTask类

时间:2021-02-10 00:12:33

Timer类是一种线程设施,可以用来实现在某一个时间或一个时间后安排某一个任务执行一次或者定期重复执行。该功能要与TimerTask配合使用。TimerTask类用来实现由Timer安排的一次或者重复执行的某一个任务。

Timer对象对用的是一个线程,因此计时器所执行的任务应该迅速完成,否则可能会延迟后续任务的执行。我们先看例1:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class Timer_TimerTask_T extends TimerTask {

	@Override
	public void run() {
		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String format = sdf.format(new Date());
		System.out.println(format);	
	}
	
	public static void main(String[] args) {
		Timer_TimerTask_T task = new Timer_TimerTask_T();
		System.out.println("主方法开始执行时间:");
		task.run();
		Timer tim=new Timer();
		System.out.println("定时任务开始执行时间:");
		tim.schedule(new Timer_TimerTask_T(), 1000*2);
	}
}

执行结果如下:

主方法开始执行时间:
2018-03-11 09:37:33
定时任务开始执行时间:
2018-03-11 09:37:35

1:要执行具体的任务,必须使用TimerTask类。TimerTask是一个抽象类,使用该类时需要自己建立一个类来继承此类,并实现其中的抽象方法。TimerTask是实现Runnable接口的,因此只要重载run()

2:Timer类在执行时,需要调用schedule()方法,方法中的参数必须有实现了TimerTask类的抽象方法的类的对象。

接下来我们在具体看Timer类中其他方法:例2:重复执行

	public static void main(String[] args) {
		Timer_TimerTask_T task = new Timer_TimerTask_T();
		Timer time=new Timer();
		System.out.println("主方法开始执行时间:");
		task.run();
		System.out.println("定时任务开始执行:");
		time.schedule(task, 1000*2,1000*1);
	}

执行结果如下:

主方法开始执行时间:
2018-03-11 09:55:42
定时任务开始执行:
2018-03-11 09:55:44
2018-03-11 09:55:45
2018-03-11 09:55:46
2018-03-11 09:55:47

从例2可见,时间的打印与2s开始,然后每间隔1s打印一次,一直重复。

例3:

public class Timer_TimerTask_T extends TimerTask {

	@Override
	public void run() {
		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String format = sdf.format(new Date());
		if("2018-03-11 10:15:20".equals(format)){
			try {
				Thread.sleep(1000 * 2);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println(format);	
	}
	
	public static void main(String[] args) {
		Timer_TimerTask_T task = new Timer_TimerTask_T();
		Timer time=new Timer();
		System.out.println("主方法开始执行时间:");
		task.run();
		System.out.println("定时任务开始执行:");
		time.scheduleAtFixedRate(task, 1000*2,1000*1);
	}
}

这个方法中使用线程进行了延时,看打印结果:

主方法开始执行时间:
2018-03-11 10:15:16
定时任务开始执行:
2018-03-11 10:15:18
2018-03-11 10:15:19
2018-03-11 10:15:20
2018-03-11 10:15:22
2018-03-11 10:15:22
2018-03-11 10:15:23
2018-03-11 10:15:24

例3_1:将例3的主方法更改如下:

public static void main(String[] args) {
		Timer_TimerTask_T task = new Timer_TimerTask_T();
		Timer time=new Timer();
		System.out.println("主方法开始执行时间:");
		task.run();
		System.out.println("定时任务开始执行:");
		time.schedule(task, 1000*2,1000*1);
	}

再看打印结果:

主方法开始执行时间:
2018-03-11 10:17:22
定时任务开始执行:
2018-03-11 10:17:24
2018-03-11 10:17:25
2018-03-11 10:17:26
2018-03-11 10:17:27
2018-03-11 10:17:28
2018-03-11 10:17:29
2018-03-11 10:17:30
2018-03-11 10:17:32
2018-03-11 10:17:33

例3和例3_1中区别在于一个调用了scheduleAtFixedRate方法,另一个调用了schedule方法,其执行结果也是有差异的。

其区别在于在重复执行任务时对于时间间隔出现延时的情况处理:

1:schedule()方法的执行时间间隔永远是固定的,如果之前出现了延时的情况,之后也会继续按照设定好的间隔时间类执行,它注重的是间隔时间的稳定。当时间为2018-03-11 10:17:30时,休眠了2s再打印时,实际时间已经到了31S,所以按照每间隔1s执行,接下来打印的是32S。

使用本方法时,在任务执行中的每一个延迟会传播到后续的任务的执行。

2:scheduleAtFixedRate()方法是以近似固定的频率重复执行,可以根据出现的延时时间自动调整下一次间隔的执行时间。李3中打印的两次2018-03-11 10:15:22几乎是同时打印的,可见这个方法注重的是执行频率的稳定性。

使用本方法时,所有后续执行根据初始执行的时间进行调度,从而希望减小延迟。

具体使用哪一个方法取决于哪些参数对你的程序或系统更重要。

关于这两个方法的区别具体说明,大家可以参考http://blog.csdn.net/ahxu/article/details/249610中的描述。

针对定时任务延时开始执行时间的参数有两种写法,一种是Date类型,另一种是Long类型,他们的作用是一样的,只是写法上的区别。例如:

		time.schedule(TimerTask task, Date delay, long period);
		time.schedule(TimerTask task, long delay, long period);
		time.schedule(task, 1000*2,1000*1);
		time.schedule(task, 1000L,1000*1);

定时器的终止:

1:调用cancle()方法,此方法Timer及TimerTask类均有。
2:调用System.exit方法,使整个程序(所有线程)终止。