定时器的应用(Timer,TimerTask)
定时器在项目当中也是会经常用到的,特别是做游戏的。比如俄罗斯方块不停的往下掉,贪吃蛇不停的往前走,人的这个移动,都是靠定时器每1秒钟,向前移动多少个像素,看起来就是一个动画效果。所以说,定时器用的也会很多。以下讲解在jdk1.5以前,使用定时器是怎么使用的。
Java用于描述定时器的类是Timer类。new Timer();就得到了一个定时器。定时器怎么启动呢?定时器是要调度的,通过schedule调度方法启动,比如第几点几分列车到站,第几点几分列车停下来,这些都是需要调度的。也就说,定时器去调度一个任务,去调度一个事件,这个事件具体的事情也是一个对象,用TimerTask类来描述。调度任务还需要指明时间,是在什么时间去干这个事。
TimerTask类:定时任务,这是一个抽象类,实现了Runnable接口,定义了一个抽象方法run。我们要执行的代码是放在一个类身上的方法里面,当我们new 一个TimerTask对象,是想执行我们的代码,也就是说,这个对象里面肯定要有一个方法,这个方法用来装我的代码。我要把一段代码交给你运行,我是怎么交的呢?我是直接把代码传给你,还是传一个对象给你?传一个对象,你拿到对象以后,调用我这个对象身上特定的某个方法去运行,我的代码也写在那个方法里面,是不是等于把我的代码教给你了。就这样的,把这个对象给他,这个对象有一个特定的方法,方法里面有代码,人家就会运行这个对象里面的特定方法代码。
public static void main(String[] args) {
new Timer().schedule(new TimerTask() {
public void run() { System.out.println("bombing!");
} }, 10000); //没有下面的代码,上面的代码一样是10秒钟过后执行任务。 while (true) { System.out.println(new Date(). try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } |
public static void main(String[] args) {
new Timer().schedule(new TimerTask() {
public void run() { System.out.println("bombing!");
} }, 10000,3000);//第一次执行任务是10秒过后,之后每隔3秒都会执行一次该任务。 } |
思考题:可不可以这样,先是过2秒钟执行一次任务,再过4秒钟执行一次任务,一直以这样的事件频率来执行任务。也就是说,每次间隔的事件不一样,要交替的出现。(思路,在定时器里面再装一个定时器)注意,当任务对象已经被调度过后,不能再调度这个任务对象了。
两种方案:
1, 根据任务执行次数的奇偶来决定叠加的触发时间。
public class TraditionalTimerTest {
private static int count = 0;
public static void main(String[] args) { class MyTimerTask extends TimerTask {
public void run() { count = (count + 1) % 2; System.out.println("bombing!"); new Timer().schedule(new MyTimerTask(), 2000 + 2000 * count); } }
new Timer().schedule(new MyTimerTask(), 2000);
while (true) { System.out.println(new Date(). try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
} |
2, 声明两种时间方法的定时器任务在run方法里面彼此调用对方的对象,实现交替执行;
public class TraditionalTimerTest2 { static class MyTimerTask2 extends TimerTask {
public void run() { System.out.println("bombing!"); new Timer().schedule(new MyTimerTask(), 4000); } }
static class MyTimerTask extends TimerTask {
public void run() { System.out.println("bombing!"); new Timer().schedule(new MyTimerTask2(), 2000); } }
public static void main(String[] args) {
new Timer().schedule(new MyTimerTask2(), 2000);
while (true) { System.out.println(new Date(). try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
} |
思考题:每天凌晨3点执行任务,这个需求怎么做?
java.util.Timer.schedule(TimerTask, Date, long),第二个参数指定某个日期的晚上3点,第三个参数指定每个24小时的毫秒数。
public void scheduleAtFixedRate(TimerTask task,
Date firstTime,
long period)
安排指定的任务在指定的时间开始进行重复的固定速率执行。以近似固定的时间间隔(由指定的周期分隔)进行后续执行。
在固定速率执行中,相对于已安排的初始执行时间来安排每次执行。如果由于任何原因(如垃圾回收或其他后台活动)而延迟了某次执行,则将快速连续地出现两次或更多次执行,从而使后续执行能够赶上来。从长远来看,执行的频率将正好是指定周期的倒数(假定 Object.wait(long) 所依靠的系统时钟是准确的)。
固定速率执行适用于那些对绝对 时间敏感的重复执行活动,如每小时准点打钟报时,或者在每天的特定时间运行已安排的维护活动。它还适用于那些完成固定次数执行的总计时间很重要的重复活动,如倒计时的计时器,每秒钟滴答一次,共 10 秒钟。最后,固定速率执行适用于安排多次重复执行的计时器任务,这些任务相互之间必须保持同步。
参数:
task
- 所要安排的任务。
firstTime
- 首次执行任务的时间。
period
- 执行各后续任务之间的时间间隔,单位是毫秒。
抛出:
IllegalArgumentException - 如果 time.getTime() 是负数。
IllegalStateException - 如果已经安排或取消了任务,已经取消了计时器,或者计时器线程已终止。
思考题:需求,定于工作日周一到周五的每天晚上的凌晨3点,收邮件。周六,周日休息,不收邮件。这个怎么实现?
这个就要使用你的数学功底了,根据日历来算了。这个就比较复杂了。可以借助开源的定时任务调度工具Quartz来实现。
Timer类:定时器
TimerTask类:定时任务,这是一个抽象类,实现了Runnable接口,定义了一个抽象方法run