欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

02_传统定时器回顾

程序员文章站 2022-05-07 17:53:02
...

传统定时器使用Timer和TimerTask组合使用

java.util.Timer:定时器,用于指定时间后任务执行一次,或者定期重复执行。

java.util.TimerTask:继承了Runnable类,本质上就是一个Runnable对象

 

Timer和TimerTask定时器主要有两种使用情景:

1)多长时间后,执行一次定时器任务

2)多长时间后,执行一次定时器任务,之后每间隔相同时间执行一次任务

 

一、定时器的使用

package com.sam;

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

/**
 * 传统定时器回顾
 * @author SAM
 *
 */
public class TraditionalTimerTask {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Timer timer = new Timer();
		timer.scheduleAtFixedRate(new TimerTask() {
			
			@Override
			public void run() {
				System.out.println("定时器 TName=" + Thread.currentThread().getName() + ",bombing!");
			}
		}, 1000L, 3000L);
		
		// 为了观察,打印当前时间
		while (true){
			System.out.println(new Date().toLocaleString());
			try {
				Thread.sleep(1000L);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

 执行结果:

 

2017-5-13 17:23:30

定时器 TName=Timer-0,bombing!

2017-5-13 17:23:32

2017-5-13 17:23:33

2017-5-13 17:23:34

定时器 TName=Timer-0,bombing!

2017-5-13 17:23:35

2017-5-13 17:23:36

2017-5-13 17:23:37

定时器 TName=Timer-0,bombing!

2017-5-13 17:23:38

2017-5-13 17:23:39

2017-5-13 17:23:40

定时器 TName=Timer-0,bombing!

 

可以看到定时器首次1秒后执行,之后每间隔3秒都会重复执行一次定时器任务。

 

二、定时器巩固

需求:2秒后执行一次任务,接着4秒后执行一次任务,然后又回到2秒后执行一次任务,

紧接着4秒又执行一次任务,如此反复,请写出代码。

 

package com.sam;

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

/**
 * 传统定时器回顾
 * 需求:2秒后执行一次任务,接着4秒后执行一次任务,然后又回到2秒后执行一次任务,
 * 紧接着4秒又执行一次任务,如此反复,请写出代码。
 * @author SAM
 *
 */
public class TraditionalTimerTask_2 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// 2秒后执行定时任务
		new Timer().schedule(new MyTimerTask(), 2000L);
		
		// 为了观察,打印当前时间
		while (true){
			System.out.println(new Date().toLocaleString());
			try {
				Thread.sleep(1000L);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

class MyTimerTask extends TimerTask{

	static int count;
	@Override
	public void run() {
		// 奇数4秒,偶数2秒
		count = ++count % 2;
		System.out.println("定时器 TName=" + Thread.currentThread().getName() + ",bombing!");
		new Timer().schedule(new MyTimerTask(), 2000L + 2000L*count);
	}
}

执行结果:

 

2017-5-13 17:45:52

2017-5-13 17:45:53

定时器 TName=Timer-0,bombing!

2017-5-13 17:45:54

2017-5-13 17:45:55

2017-5-13 17:45:56

2017-5-13 17:45:57

定时器 TName=Timer-1,bombing!

2017-5-13 17:45:58

2017-5-13 17:45:59

定时器 TName=Timer-2,bombing!

2017-5-13 17:46:00

2017-5-13 17:46:01

2017-5-13 17:46:02

2017-5-13 17:46:03

定时器 TName=Timer-3,bombing!

 

接着再深入Timer类一些细节,Timer有两组启动定时器任务的方法,他们可能比较费解:

1)schedule(TimerTask task, long delay, long period) 

2)scheduleAtFixedRate(TimerTask task, long delay, long period) 

 

区别:

他们都可以实现:多长时间后,执行一次定时器任务,之后每间隔相同时间执行一次任务;

但是他们又有一些本质的区别,首先schedule是固定延期执行,而scheduleAtFixedRate是固定速率执行。

 

再具体说:

1)固定延期,根据前一次执行的实际时间来安排每一次执行。

如果由于任何原因(如垃圾回收或者其他后台活动)而延迟了某次执行,则后续执行也将延迟。

 

2)固定速率,根据已安排的初始执行时间来安排每次执行。

如果由于任何原因(如垃圾回收或者其他后台活动)而延迟了某次执行,

则将快速连续执行两次或者更多任务,从而使后续执行能够“追赶上来”。

注意这时TimerTask的执行需要考虑同步。

 

最后推荐一个开源项目,quartz,主要用来实现复杂的调度需求。

例如周一至周五早上10点定时收邮件,周六日不收邮件,

这时使用Timer和TimerTask可能比较复杂,使用quartz开源项目可以很容易的解决这类需求。