Timer的 schedule 和 scheduleAtFixedRate 方法辨析—————修正上篇博文

Timer的schedule和scheduleAtFixedRate方法辨析,有需要的朋友可以参考下。


首先我们来看看在API中是如何描述java.util.Timer类的。(以下摘自Java 1.5 API )

与每个 Timer 对象相对应的是单个后台线程,用于顺序地执行所有计时器任务。计时器任务应该迅速完成。如果完成某个计时器任务的时间太长,那么它会“独占”计时器的任务执行线程。因此,这就可能延迟后续任务的执行,而这些任务就可能“堆在一起”,并且在上述令人讨厌的任务最终完成时才能够被快速连续地执行。对 Timer 对象最后的引用完成后,并且所有未处理的任务都已执行完成后,计时器的任务执行线程会正常终止(并且成为垃圾回收的对象)。但是这可能要很长时间后才发生。默认情况下,任务执行线程并不作为守护线程来运行,所以它能够阻止应用程序终止。如果调用方想要快速终止计时器的任务执行线程,那么调用方应该调用计时器的 cancel 方法。如果意外终止了计时器的任务执行线程,例如调用了它的 stop 方法,那么所有以后对该计时器安排任务的尝试都将导致 IllegalStateException,就好像调用了计时器的 cancel 方法一样。此类是线程安全的:多个线程可以共享单个 Timer 对象而无需进行外部同步。

Timer中的void schedule(TimerTask task, Date firstTime,long period) ,

API描述:安排指定的任务在指定的时间开始进行重复的固定延迟执行。

Timer中的void scheduleAtFixedRate(TimerTask task, Date firstTime, long period),

API描述:安排指定的任务在指定的时间开始进行重复的固定速率执行。。

大家这两个描述,可以看出什么不同来吗?至少我是没有看出来哈!现在我就用一个典型的案例来辨析一下这两者的不同之处!

1.void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) 方法测试:

public class Test {
public static void main(String[] args) throws ParseException {
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 
Date startDate = dateFormatter.parse("2010/11/28 01:06:00");
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask(){
public void run() {
System.out.println("进入任务的时间: "+new Date());
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
///注意这里是安排任务应该执行的时间
System.out.println("计划开始执行execute task: "+ new Date(this.scheduledExecutionTime()));
//注意这里是任务实际的执行时间
System.out.println("任务结束时间: "+new Date());
}
},startDate, 2* 1000);
}
}

说明:scheduledExecutionTime()方法返回此任务最近实际 执行的安排 执行时间。

这是在任务实际执行时间>程序设定的间隔时间 的情况下!

执行结果:

进入任务的时间: Thu Feb 13 15:39:26 CST 2014
计划开始执行execute task: Sun Nov 28 01:06:00 CST 2010
任务结束时间: Thu Feb 13 15:39:30 CST 2014
进入任务的时间: Thu Feb 13 15:39:30 CST 2014
计划开始执行execute task: Sun Nov 28 01:06:02 CST 2010
任务结束时间: Thu Feb 13 15:39:34 CST 2014
进入任务的时间: Thu Feb 13 15:39:34 CST 2014
计划开始执行execute task: Sun Nov 28 01:06:04 CST 2010
任务结束时间: Thu Feb 13 15:39:38 CST 2014
进入任务的时间: Thu Feb 13 15:39:38 CST 2014
计划开始执行execute task: Sun Nov 28 01:06:06 CST 2010
任务结束时间: Thu Feb 13 15:39:42 CST 2014
进入任务的时间: Thu Feb 13 15:39:42 CST 2014
计划开始执行execute task: Sun Nov 28 01:06:08 CST 2010
任务结束时间: Thu Feb 13 15:39:46 CST 2014
进入任务的时间: Thu Feb 13 15:39:46 CST 2014

修改程序参数后如下:

public class Test {
public static void main(String[] args) throws ParseException {
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 
Date startDate = dateFormatter.parse("2010/11/28 01:06:00");
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask(){
public void run() {
System.out.println("进入任务的时间: "+new Date());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
///注意这里是安排任务应该执行的时间
System.out.println("计划开始执行execute task: "+ new Date(this.scheduledExecutionTime()));
//注意这里是任务实际的执行时间
System.out.println("任务结束时间: "+new Date());
}
},startDate, 4* 1000);
}
}

执行结果:

进入任务的时间: Thu Feb 13 15:52:04 CST 2014
计划开始执行execute task: Sun Nov 28 01:06:00 CST 2010
任务结束时间: Thu Feb 13 15:52:06 CST 2014
进入任务的时间: Thu Feb 13 15:52:06 CST 2014
计划开始执行execute task: Sun Nov 28 01:06:04 CST 2010
任务结束时间: Thu Feb 13 15:52:08 CST 2014
进入任务的时间: Thu Feb 13 15:52:08 CST 2014
计划开始执行execute task: Sun Nov 28 01:06:08 CST 2010
任务结束时间: Thu Feb 13 15:52:10 CST 2014
进入任务的时间: Thu Feb 13 15:52:10 CST 2014
计划开始执行execute task: Sun Nov 28 01:06:12 CST 2010
任务结束时间: Thu Feb 13 15:52:12 CST 2014
进入任务的时间: Thu Feb 13 15:52:12 CST 2014
计划开始执行execute task: Sun Nov 28 01:06:16 CST 2010
任务结束时间: Thu Feb 13 15:52:14 CST 2014
进入任务的时间: Thu Feb 13 15:52:14 CST 2014
计划开始执行execute task: Sun Nov 28 01:06:20 CST 2010
任务结束时间: Thu Feb 13 15:52:16 CST 2014
进入任务的时间: Thu Feb 13 15:52:16 CST 2014

由此可以肯定的是:

(1)void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)方法的任务的计划执行时间是从firstTime开始计算的。第一次:firstTime,第二次:firstTime+period.以此类推。

(2)void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)方法的下一个任务的实际开始执行时间=上一任务的实际开始执行时间+(实际执行时间与时间间隔中的最大值)。

2.void schedule(TimerTask task, Date firstTime,long period) 测试:

public class Test2 {
public static void main(String[] args) throws ParseException {
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 
Date startDate = dateFormatter.parse("2010/11/28 01:06:00");
Timer timer = new Timer();
timer.schedule(new TimerTask(){
public void run() {
try {
System.out.println("进入任务的时间: "+new Date());
//任务执行时间2秒
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//注意这里是安排任务应该执行的时间
System.out.println("计划开始执行execute task: "+ new Date(this.scheduledExecutionTime()));
//注意这里是任务实际的执行时间
System.out.println("任务结束时间: "+new Date());
}
},startDate,4* 1000);
}
}

执行结果:

进入任务的时间: Thu Feb 13 15:57:38 CST 2014
计划开始执行execute task: Thu Feb 13 15:57:38 CST 2014
任务结束时间: Thu Feb 13 15:57:40 CST 2014
进入任务的时间: Thu Feb 13 15:57:42 CST 2014
计划开始执行execute task: Thu Feb 13 15:57:42 CST 2014
任务结束时间: Thu Feb 13 15:57:44 CST 2014
进入任务的时间: Thu Feb 13 15:57:46 CST 2014
计划开始执行execute task: Thu Feb 13 15:57:46 CST 2014
任务结束时间: Thu Feb 13 15:57:48 CST 2014
进入任务的时间: Thu Feb 13 15:57:50 CST 2014
计划开始执行execute task: Thu Feb 13 15:57:50 CST 2014
任务结束时间: Thu Feb 13 15:57:52 CST 2014

注意年份没有变化!

这时候任务执行时间<间隔时间 (2000>4000)!

上一个任务结束后等待2秒再进入下一个任务。

现在修改一下参数:

public class Test2 {
public static void main(String[] args) throws ParseException {
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 
Date startDate = dateFormatter.parse("2010/11/28 01:06:00");
Timer timer = new Timer();
timer.schedule(new TimerTask(){
public void run() {
try {
System.out.println("进入任务的时间: "+new Date());
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//注意这里是安排任务应该执行的时间
System.out.println("计划开始执行execute task: "+ new Date(this.scheduledExecutionTime()));
//注意这里是任务实际的执行时间
System.out.println("任务结束时间: "+new Date());
}
},startDate,2* 1000);
}
}

执行结果:

进入任务的时间: Thu Feb 13 16:02:11 CST 2014
计划开始执行execute task: Thu Feb 13 16:02:11 CST 2014
任务结束时间: Thu Feb 13 16:02:15 CST 2014
进入任务的时间: Thu Feb 13 16:02:15 CST 2014
计划开始执行execute task: Thu Feb 13 16:02:15 CST 2014
任务结束时间: Thu Feb 13 16:02:19 CST 2014
进入任务的时间: Thu Feb 13 16:02:19 CST 2014
计划开始执行execute task: Thu Feb 13 16:02:19 CST 2014
任务结束时间: Thu Feb 13 16:02:23 CST 2014
进入任务的时间: Thu Feb 13 16:02:23 CST 2014
计划开始执行execute task: Thu Feb 13 16:02:23 CST 2014
任务结束时间: Thu Feb 13 16:02:27 CST 2014
进入任务的时间: Thu Feb 13 16:02:27 CST 2014
计划开始执行execute task: Thu Feb 13 16:02:27 CST 2014
任务结束时间: Thu Feb 13 16:02:31 CST 2014
进入任务的时间: Thu Feb 13 16:02:31 CST 2014

注意:这时候 任务执行时间>间隔时间 (4000>2000)!

上一个任务结束后马上进入下一个任务。

由此可以推出:void schedule(TimerTask task, Date firstTime,long period)方法的任务的计划执行时间是从第一次实际执行任务开始计算的。

a. 当任务执行时间>间隔时间时,第一次计划执行时间=第一次实际开始执行任务的时间,第二次计划执行时间==上一次开始执行时间+任务执行时间。以此类推。

b.当任务执行时间<间隔时间时,第一次计划执行时间=第一次实际开始执行任务的时间,第二次计划执行时间=上一次开始执行时间+间隔时间。以此类推。

这同时也论证了API描述部分说的任务执行时间长时会产生累计延迟的效果。

结论:void schedule(TimerTask task, Date firstTime,long period) 方法与void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)方法的不同之处在于计划执行时间的方式不一样。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值