schedule和scheduleAtFixedRate的区别:
- schedule為「fixed-delay」,執行時間參照前次工作執行完成的時間:
若執行工作沒被 delay,則按照預訂的時間執行;但若執行工作時被 delay了,
随後工作的預訂執行時間會按照上一次執行「完成」的時間點來計算。 - scheduleAtFixedRate為「fixed-rate」,執行時間參照一開始的時間點;
和schedule一樣,若執行工作沒被 delay,則按照預訂的時間執行;
但如果執行工作時被delay了,
後續的預訂執行時間仍按照上一次執行「開始」的時間點計算,
且為了「catch up」預訂時間,會連續多次補足未完成的任務!
另外在在單次執行的情況下,
只要預訂要執行的時間已經過了,那麼兩者都會直接把工作移除不執行。
但若在有設定 period 的情況下,若預訂要執行的時間已經過了,
基於上面所描述的行為,schedule 沒有上次執行完成的時間,會從現在開始算並執行,
而 scheduleAtFixedRate 則以預訂執行的時間開始算,且會一口氣將過去未做的補上!
下面是工作 Task 的程式碼,每次進到工作時會 random 睡上 4~8秒才結束。
class DelayTimer extends TimerTask { public void run() { System.out.println("-------------DelayTimer开始-------------------------"); System.out.println("Task 预定开始时间:" + dateFormat(new Date(this.scheduledExecutionTime()), "yyyy-MM-dd HH:mm:ss") + ", \n实际开始时间:" + dateFormat(new Date(), "yyyy-MM-dd HH:mm:ss")); try { int sleepSeconds = (int) (4 + Math.random() * 4); System.out.println("Task going to sleep " + sleepSeconds + "s."); Thread.sleep(sleepSeconds * 1000); } catch (InterruptedException e) { } System.out.println("-------------DelayTimer结束-------------------------"); } }
下面則是測試程式的程式碼,預訂的時間間隔為 5秒:
void testSchedule() { Timer timer = new Timer(); System.out.println("In testSchedule:" +dateFormat(new Date(), "yyyy-MM-dd HH:mm:ss")); System.out.println("Delay:5秒, Period:5秒"); // schedule(TimerTask task, long delay, long period) timer.schedule(new DelayTimer(), new Date(), 5000); try { Thread.sleep(30000); } catch (InterruptedException e) { } timer.cancel(); System.out.println("End testSchedule:" + dateFormat(new Date(), "yyyy-MM-dd HH:mm:ss") + "\n"); } void testScheduleAtFixedRate() { Timer timer = new Timer(); System.out.println("In testScheduleAtFixedRate:" + dateFormat(new Date(), "yyyy-MM-dd HH:mm:ss")); System.out.println("Delay:5秒, Period:5秒"); // scheduleAtFixedRate(TimerTask task, long delay, long period) timer.scheduleAtFixedRate(new DelayTimer(), new Date(), 5000); try { Thread.sleep(30000); } catch (InterruptedException e) { } timer.cancel(); System.out.println("End testScheduleAtFixedRate:" + dateFormat(new Date(), "yyyy-MM-dd HH:mm:ss") + "\n"); } String dateFormat(Date date, String format) { String result = null; try { if (date == null) { result = ""; } else { SimpleDateFormat sdf = new SimpleDateFormat(format); result = sdf.format(date).toString(); } } catch (Exception e) { e.printStackTrace(); } return result; }
執行結果:
首先來看 schedule 的部份,由下面的資料我們可以發現,
當工作執行時間超過 5 秒時,下次的預訂執行時間會以工作結束的時間來計算,
如下面標紅色部份,工作執行了 7秒,則下次的預訂時間就晚 7秒,
而若工作時間少於 5 秒,下次執行的間隔仍維持 5 秒,如下面標藍色部份。
對 schedule 而言,所有預訂和實際執行時間都是相同的,沒有 catch up 的情況。
In testSchedule:2014-09-04 09:06:04
Delay:5秒, Period:5秒
-------------DelayTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:06:04,
实际开始时间:2014-09-04 09:06:04
Task going to sleep 7s.
-------------DelayTimer结束-------------------------
-------------DelayTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:06:11,
实际开始时间:2014-09-04 09:06:11
Task going to sleep 5s.
-------------DelayTimer结束-------------------------
-------------DelayTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:06:16,
实际开始时间:2014-09-04 09:06:16
Task going to sleep 4s.
-------------DelayTimer结束-------------------------
-------------DelayTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:06:21,
实际开始时间:2014-09-04 09:06:21
Task going to sleep 6s.
-------------DelayTimer结束-------------------------
-------------DelayTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:06:27,
实际开始时间:2014-09-04 09:06:27
Task going to sleep 6s.
-------------DelayTimer结束-------------------------
-------------DelayTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:06:33,
实际开始时间:2014-09-04 09:06:33
Task going to sleep 5s.
End testSchedule:2014-09-04 09:06:34
而對 scheduleAtFixedRate 來說,
當工作執行時間超過 5 秒時,下次的預訂執行時間仍以工作開始的時間來計算,
所以所有後續工作的預訂時間都是間隔 5秒,然而排程的工作不會同時執行,
故雖然預訂時間間隔5秒,但實際執行時間會被 delay,如下面標紅色部份,
工作執行了 6秒,則下次的預訂時間是5秒後,但實際執行是6秒後。
這個預訂時間和實際執行時間的差距,將在後續的工作排程中產生影響,
在實際執行時間落後預訂時間時,scheduleAtFixedRate 會有 catch up 的機制,
在後續若執行時間較短,我們就可以發現執行的間距小於 5秒,如藍色所示。
In testScheduleAtFixedRate:2014-09-04 09:06:34
Delay:5秒, Period:5秒
-------------DelayTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:06:34,
实际开始时间:2014-09-04 09:06:34
Task going to sleep 4s.
-------------DelayTimer结束-------------------------
-------------DelayTimer结束-------------------------
-------------DelayTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:06:39,
实际开始时间:2014-09-04 09:06:39
Task going to sleep 7s.
-------------DelayTimer结束-------------------------
-------------DelayTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:06:44,
实际开始时间:2014-09-04 09:06:46
Task going to sleep 7s.
-------------DelayTimer结束-------------------------
-------------DelayTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:06:49,
实际开始时间:2014-09-04 09:06:53
Task going to sleep 6s.
-------------DelayTimer结束-------------------------
-------------DelayTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:06:54,
实际开始时间:2014-09-04 09:06:59
Task going to sleep 4s.
-------------DelayTimer结束-------------------------
-------------DelayTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:06:59,
实际开始时间:2014-09-04 09:07:03
Task going to sleep 5s.
End testScheduleAtFixedRate:2014-09-04 09:07:04
-------------DelayTimer结束-------------------------
看完了以上的例子,我們發現 schedule 和 scheduleAtFixedRate都不會同時執行,
而是接續著執行,所以不須考慮同步的問題。
接下來我們再來看看若預訂執行的時間已經過了,兩個不同 method 有何差異,
這也會展示 catch up 的影響到底有多大:
這次我們不再需要不同的工作時間,所以工作的程式碼簡化如下:
class NormalTimer extends TimerTask { public void run() { System.out.println("-------------NormalTimer开始-------------------------"); System.out.println("Task 预定开始时间:" + dateFormat(new Date(this.scheduledExecutionTime()), "yyyy-MM-dd HH:mm:ss") + ", \n实际开始时间:" + dateFormat(new Date(), "yyyy-MM-dd HH:mm:ss")); System.out.println("-------------NormalTimer结束-------------------------"); } }
测试代码如下:
void testSchedulePassedDate() { Timer timer = new Timer(); System.out.println("In testSchedule:" +dateFormat(new Date(), "yyyy-MM-dd HH:mm:ss")); System.out.println("Period:5秒"); // 設定填入schedule中的 Date firstTime // 為現在的15秒前 Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.SECOND, calendar.get(Calendar.SECOND)-15); Date firstTime = calendar.getTime(); // schedule(TimerTask task, Date firstTime, long period) timer.schedule(new NormalTimer(), firstTime, 5000); try { Thread.sleep(30000); } catch (InterruptedException e) { } timer.cancel(); System.out.println("End testSchedule:" + dateFormat(new Date(), "yyyy-MM-dd HH:mm:ss") + "\n"); } void testScheduleAtFixedRatePassedDate() { Timer timer = new Timer(); System.out.println("In testScheduleAtFixedRate:" + dateFormat(new Date(), "yyyy-MM-dd HH:mm:ss")); System.out.println("Period:5秒"); // 設定填入schedule中的 Date firstTime // 為現在的15秒前 Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.SECOND, calendar.get(Calendar.SECOND)-15); Date firstTime = calendar.getTime(); // scheduleAtFixedRate(TimerTask task, Date firstTime, long period) timer.scheduleAtFixedRate(new NormalTimer(), firstTime, 5000); try { Thread.sleep(30000); } catch (InterruptedException e) { } timer.cancel(); System.out.println("End testScheduleAtFixedRate:" + dateFormat(new Date(), "yyyy-MM-dd HH:mm:ss") + "\n"); }
執行的結果為:
In testSchedule:2014-09-04 09:31:40
Period:5秒
-------------NormalTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:31:40,
实际开始时间:2014-09-04 09:31:40
-------------NormalTimer结束-------------------------
-------------NormalTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:31:45,
实际开始时间:2014-09-04 09:31:45
-------------NormalTimer结束-------------------------
-------------NormalTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:31:50,
实际开始时间:2014-09-04 09:31:50
-------------NormalTimer结束-------------------------
-------------NormalTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:31:55,
实际开始时间:2014-09-04 09:31:55
-------------NormalTimer结束-------------------------
-------------NormalTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:32:00,
实际开始时间:2014-09-04 09:32:00
-------------NormalTimer结束-------------------------
-------------NormalTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:32:05,
实际开始时间:2014-09-04 09:32:05
-------------NormalTimer结束-------------------------
End testSchedule:2014-09-04 09:32:10
In testScheduleAtFixedRate:2014-09-04 09:32:10
Period:5秒
-------------NormalTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:31:55,
实际开始时间:2014-09-04 09:32:10
-------------NormalTimer结束-------------------------
-------------NormalTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:32:00,
实际开始时间:2014-09-04 09:32:10
-------------NormalTimer结束-------------------------
-------------NormalTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:32:05,
实际开始时间:2014-09-04 09:32:10
-------------NormalTimer结束-------------------------
-------------NormalTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:32:10,
实际开始时间:2014-09-04 09:32:10
-------------NormalTimer结束-------------------------
-------------NormalTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:32:15,
实际开始时间:2014-09-04 09:32:15
-------------NormalTimer结束-------------------------
-------------NormalTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:32:20,
实际开始时间:2014-09-04 09:32:20
-------------NormalTimer结束-------------------------
-------------NormalTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:32:25,
实际开始时间:2014-09-04 09:32:25
-------------NormalTimer结束-------------------------
-------------NormalTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:32:30,
实际开始时间:2014-09-04 09:32:30
-------------NormalTimer结束-------------------------
-------------NormalTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:32:35,
实际开始时间:2014-09-04 09:32:35
-------------NormalTimer结束-------------------------
-------------NormalTimer开始-------------------------
Task 预定开始时间:2014-09-04 09:32:40,
实际开始时间:2014-09-04 09:32:40
-------------NormalTimer结束-------------------------
End testScheduleAtFixedRate:2014-09-04 09:32:40
由上面的結果我們可以發現當現在的時間已經超過指定的 date 時,
schedule 會直接從現在開始做,且沒有 catch up 的情況。
而 scheduleAtFixedRate 則會發生 catch up,即他會想要趕上預訂的執行時間,
所以已過期的任務仍會被執行,這也是為何藍色部份會在一開始被執行連續被執行。
從以上所有的測試結果來看,兩者主要的差異有兩點:
- 執行工作時間較預訂工作間隔長時:
schedule 會直接 delay 後續的工作預訂的時間;
scheduleAtFixedRate 後續工作的預訂時間仍按工作間隔計算,
後續若有工作提早完成,會以 catch up 來追上預訂時間。 - 執行任務已過期時:
若只執行單次不repeat,則兩者都不會執行;但若有 repeat,
schedule 不會管前面過期的任務,直接由當下開始執行並計算後續的工作時間;
scheduleAtFixedRate 則一樣以 catch up 機制,會先補足前面未完成的部份。
本文参考自 http://www.ewdna.com/2011/12/java-timerschedulescheduleatfixedrate.html
相关推荐
Java 中 Timer 的 schedule 和 scheduleAtFixedRate 方法区别详解 Java 中的 Timer 类提供了两个常用的方法:schedule 和 scheduleAtFixedRate,用于安排和执行定时任务。虽然这两个方法看起来很相似,但是它们之间...
Timer类有两种执行任务的模式:schedule和scheduleAtFixedRate。schedule模式可以在某个时间或固定的时间延迟后执行任务,而scheduleAtFixedRate模式可以让任务在固定的频率下运行。 schedule模式的使用方法如下所...
在Java编程语言中,`Timer`和`TimerTask`是两个重要的类,它们用于调度周期性的任务执行。这两个类属于`java.util`包,提供了在后台线程中延迟执行任务或者定期执行任务的能力,这对于创建定时任务或者实现定时器...
在Java编程语言中,`Timer`和`TimerTask`是两个关键类,它们用于调度周期性的任务执行。这两个类在多线程环境下尤其有用,能够帮助开发者安排在将来某一特定时间或定期执行的任务。让我们深入了解一下`Timer`和`...
Java.util.Timer类是Java标准库提供的一种简单但功能有限的定时任务执行机制。它允许开发者在指定的时间间隔或特定时间点执行任务,非常适合处理一次性或周期性的后台操作。本篇文章将深入探讨如何使用Timer和...
Java并发编程是Java编程中一个非常重要的方面,java.util.Timer是Java中的一个基本组件,用于实现延时和周期性任务的执行。但是,Timer存在一些缺陷,如创建唯一的线程来执行所有Timer任务,如果一个timer任务的执行...
在本文中,我们将深入探讨`Timer`类的基本使用和示例,帮助你理解如何在Java程序中实现简单的定时任务。 首先,`Timer`类提供了计划任务的能力,它可以按照预定的时间间隔安排任务执行。创建一个`Timer`对象后,你...
Java Schedule 是Java编程语言中用于实现定时任务的重要概念,它主要涉及到Java的并发处理和计划任务执行。在Java中,我们可以使用多种库和工具来创建和管理定时任务,如Java的内置API `java.util.Timer` 和 `java....
使用Timer对象的schedule()或scheduleAtFixedRate()方法安排任务执行。schedule()方法用于单次执行,scheduleAtFixedRate()方法用于周期性执行。例如: - 单次执行: ```java TimerTask myTask = new MyTask(); ...
Java定时器(Java Timer)是Java SE平台中的一个强大工具,用于在特定时间间隔执行任务。这个类位于`java.util`包中,提供了调度任务的能力,使得开发者可以安排任务在未来某个时间点或定期执行。在Java中,定时任务...
`Timer` 类提供了两种计划任务的方法:`schedule(TimerTask task, long delay)` 和 `scheduleAtFixedRate(TimerTask task, long delay, long period)`。前者会在指定的延迟后执行一次任务,而后者则会按照固定的延迟...
5. schedule()和scheduleAtFixedRate()的区别:schedule()方法用于实现循环调度,而scheduleAtFixedRate()方法用于实现固定速率的调度。两者之间的区别在于schedule()方法会考虑到任务执行的时间,而...
- 创建一个`Timer`对象后,可以通过调用其`schedule()`或`scheduleAtFixedRate()`方法来安排任务执行。 2. **TimerTask类**: - `TimerTask`是一个抽象类,代表一个可由`Timer`计划的任务。你需要创建它的子类并...
Java定时器(Timer)是Java.util包中的一个类,它提供了调度任务的能力,可以在特定的延迟后或定期执行。在Java编程中,我们有时需要在指定时间执行某些操作,例如发送提醒、执行清理任务等,这时候Java Timer就派上...
`Timer` 和 `TimerTask` 是Java中用于实现定时任务的重要工具。它们提供了一种简单有效的方式来安排任务的执行,既可以一次性执行也可以周期性地执行。这对于实现定时提醒、定时备份等功能非常有用。 #### 二、...
Java中的Timer和TimerTask简介(附完整代码实例)。 在Java中,Timer和TimerTask是两个经常用来实现定时器的类。这两个类使用起来非常方便,可以完成我们对定时器的绝大多数需求。 Timer是一种定时器工具,用来在一...
总的来说,`Timer`和`TimerTask`是Java中实现简单定时任务的便利工具,但在高并发、高性能的场景下,可能需要考虑使用更强大的调度库,如`Quartz`或`Spring Framework`中的`ScheduledExecutorService`。
它包含两个核心方法:schedule(TimerTask task, long delay)和scheduleAtFixedRate(TimerTask task, long initialDelay, long period)。前者在指定延迟后首次执行任务,而后者则会按固定的间隔重复执行任务。 ...
在Java编程语言中,`Timer`类是Java.util包下的一个关键组件,它提供了一种在后台线程中调度任务的能力。这个简单的“timer例子”很适合初学者学习,了解如何在程序中设置延迟执行或周期性执行任务。在这个实例中,...