時間:2017年05月24日星期三
說明:本文部份內容均來自慕課網。@慕課網:http://www.imooc.com
教學示例源碼:無
我的學習源碼:https://github.com/zccodere/s...java
什麼是定時任務調度git
基於給定的時間點,給定的時間間隔或者給定的執行次數自動執行的任務
在Java中的定時調度工具github
Timer:小弟,能實現平常60%的定時任務 Quartz:大哥,能搞定一切
Timer與Quartz區別架構
出身不一樣 Timer由JDK提供,調用方式簡單粗暴,不須要別的jar包支持 Quartz源於開源項目,非JDK自帶,須要引入別的jar包支持 能力區別:主要體如今對時間的控制上 Timer實現如某個具體時間執行什麼任務 Quartz實現如每一個星期天8點執行什麼任務 Quartz的時間控制功能遠比Timer強大和完善 底層機制 Timer走後臺線程執行定時任務 Quartz可以使用多個執行線程去執行定時任務 Quartz確實比Timer強大不少,可是,Timer能實現的功能,儘可能不動用Quartz 畢竟大哥的出場費要比小弟高
前置知識併發
本節內容app
Timer紙上談兵:Timer的定義以及架構 Timer實戰演練:經過一個實際的例子,讓你們對Timer有一個初步的瞭解
Timer的定義ide
有且僅有一個後臺線程對多個業務線程進行定時定頻率的調度
主要構件函數
Timer工具類詳解工具
經過程序來說解Timer學習
代碼演示
1.編寫需定時調度的業務邏輯類
package com.myimooc.timer; import java.util.TimerTask; /** * 需定時調度的業務邏輯類 * Created by ChangComputer on 2017/5/24. */ // 繼承 TimerTask 類 public class MyTimerTask extends TimerTask{ private String name; public MyTimerTask(String name){ this.name = name; } // 重寫 run 方法 @Override public void run() { // 打印當前 name 的內容 System.out.println("Current exec name is : " + name); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
2.編寫定時調度類
package com.myimooc.timer; import java.util.Timer; /** * 定時調度類 * Created by ChangComputer on 2017/5/24. */ public class MyTimer { public static void main(String[] args){ // 建立一個 Timer 實例 Timer timer = new Timer(); // 建立一個 MyTimerTask 實例 MyTimerTask myTimerTask = new MyTimerTask("No.1"); // 經過 Timer 定時定頻率調用 MyTimerTask 的業務邏輯 // 即第一次執行是在當前時間的兩秒以後,以後每隔一秒鐘執行一次 timer.schedule(myTimerTask,2000L,1000L); } }
本節內容
schedule的四種用法 scheduleAtFixedRate的兩種用法
第一種用法:schdule(task, time)
參數 task:所要安排的任務 time:執行任務的時間 做用 在時間等於或者超過time的時候執行且僅執行一次task
第二種用法:schedule(task, time, period)
參數 task:所要安排的任務 time:首次執行任務的時間 period:執行一次task的時間間隔,單位是毫秒 做用 時間等於或者超過time時首次執行task 以後每隔period毫秒重複執行一次task
第三種用法:schedule(task, delay)
參數 task:所要安排的任務 delay:執行任務前的延遲時間,單位是毫秒 做用 等待delay毫秒後僅執行且執行一個task
第四種用法:schedule(task, delay, period)
參數 task:所要安排的任務 delay:執行任務前的延遲時間,單位是毫秒 period:執行一次task的時間間隔,單位是毫秒 做用 等到delay毫秒後首次執行task 以後每隔period毫秒重複執行一次task
第一種用法:scheduleAtFixedRate(task, time, period)
參數 task:所要安排的任務 time:首次執行任務的時間 period:執行一次task的時間間隔,單位是毫秒 做用 時間等於或超過time時首次執行task 以後每隔period毫秒重複執行一次task
第二種用法:scheduleAtFixedRate(task, delay, period)
參數 task:所要安排的任務 delay:執行任務前的延遲時間,單位是毫秒 period:執行一次task的時間間隔,單位是毫秒 做用 等到delay毫秒後首次執行task 以後每隔period毫秒重複執行一次task
代碼演示
1.修改需定時調度的業務邏輯類
/** * 需定時調度的業務邏輯類 * Created by ChangComputer on 2017/5/24. */ // 繼承 TimerTask 類 public class MyTimerTask extends TimerTask{ private String name; public MyTimerTask(String name){ this.name = name; } // 重寫 run 方法 @Override public void run() { // 以yyyy-MM-dd HH:mm:ss的格式打印當前執行時間 // 如2016-11-11 00:00:00 Calendar calendar = Calendar.getInstance(); // 定義日期格式 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current exec time is : " + simpleDateFormat.format(calendar.getTime())); // 打印當前 name 的內容 System.out.println("Current exec name is : " + name); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
2.修改定時調度類
package com.myimooc.timer; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Timer; /** * 定時調度類 * Created by ChangComputer on 2017/5/24. */ public class MyTimer { public static void main(String[] args){ // 建立一個 Timer 實例 Timer timer = new Timer(); // 建立一個 MyTimerTask 實例 MyTimerTask myTimerTask = new MyTimerTask("No.1"); // 經過 Timer 定時定頻率調用 MyTimerTask 的業務邏輯 // 即第一次執行是在當前時間的兩秒以後,以後每隔一秒鐘執行一次 //timer.schedule(myTimerTask,2000L,1000L); /** * 獲取當前時間,並設置成距離當前時間三秒以後的時間 * 如當前時間是2016-11-10 23:59:57 * 則設置後的時間則爲2016-11-11 00:00:00 */ Calendar calendar = Calendar.getInstance(); // 定義日期格式 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current exec time is : " + simpleDateFormat.format(calendar.getTime())); calendar.add(Calendar.SECOND,3); // schedule的四種用法 /** * 1.在時間等於或超過time的時候執行僅且執行一次task * 如在2016-11-11 00:00:00執行一次task,打印任務名字 */ //myTimerTask.setName("schedule1"); //timer.schedule(myTimerTask,calendar.getTime()); /** * 2.時間等於或超過time首次執行task * 以後每隔period毫秒重複執行一次task * 如在2016-11-11 00:00:00第一次執行task,打印任務名字 * 以後每隔兩秒執行一次task */ //myTimerTask.setName("schedule2"); //timer.schedule(myTimerTask,calendar.getTime(),2000L); /** * 3.等待delay毫秒後僅執行且執行一個task * 如如今是2016-11-11 00:00:00 * 則在2016-11-11 00:00:01執行一次task,打印任務名字 */ //myTimerTask.setName("schedule3"); //timer.schedule(myTimerTask,1000L); /** * 4.等到delay毫秒後首次執行task * 以後每隔period毫秒重複執行一次task * 如如今是2016-11-11 00:00:00 * 則在2016-11-11 00:00:01第一次執行task,打印任務名字 * 以後每隔兩秒執行一次task */ //myTimerTask.setName("schedule4"); //timer.schedule(myTimerTask,1000L,2000L); // scheduleAtFixedRate的兩種用法 /** * 1.時間等於或超過time時首次執行task * 以後每隔period毫秒重複執行一次task * 如在2016-11-11 00:00:00第一次執行task,打印任務名字 * 以後每隔兩秒執行一次task */ //myTimerTask.setName("scheduleAtFixedRate1"); //timer.scheduleAtFixedRate(myTimerTask,calendar.getTime(),2000L); /** * 2.等待delay毫秒後首次執行task * 以後每隔period毫秒重複執行一次task * 如如今是2016-11-11 00:00:00 * 則在2016-11-11 00:00:01第一次執行task,打印任務名字 * 以後每隔兩秒執行一次task */ myTimerTask.setName("scheduleAtFixedRate2"); timer.scheduleAtFixedRate(myTimerTask,1000L,2000L); } }
本節內容
TimerTask的cancel(), scheduleExecutionTime() Timer的cancel(), purge()
TimerTask類的cancel()
做用 取消當前TimerTask裏的任務
TimerTask類的scheduleExecutionTime()
做用 返回此任務最近實際執行的已安排執行的時間 返回值 最近發生此任務執行安排的時間,爲long型
Timer的cancel()
做用 終止此計時器,丟棄全部當前已安排的任務
Timer的purge()
做用 今後計時器的任務隊列中移除全部已取消的任務 返回值 從隊列中移除的任務數
代碼演示
package com.myimooc.timer; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; /** * Created by ChangComputer on 2017/5/24. */ public class CancelTest { public static void main(String[] args) throws InterruptedException { // 建立Timer實例 Timer timer = new Timer(); // 建立TimerTask實例 MyTimerTask task1 = new MyTimerTask("task1"); MyTimerTask task2 = new MyTimerTask("task2"); // 獲取當前的執行時間並打印 Date startTime = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("start time is : " + simpleDateFormat.format(startTime)); // task1首次執行是距離如今時間3秒後執行,以後每隔2秒執行一次 // task1首次執行是距離如今時間1秒後執行,以後每隔2秒執行一次 timer.schedule(task1,3000L,2000L); timer.schedule(task2,1000L,2000L); System.out.println("current canceled task number is : " + timer.purge()); // 休眠5秒 Thread.sleep(2000L); // 獲取當前的執行時間並打印 Date cancelTime = new Date(); System.out.println("cancel time is : " + simpleDateFormat.format(cancelTime)); // 取消全部任務 // timer.cancel(); task2.cancel(); //System.out.println("Tasks all canceled!"); System.out.println("current canceled task number is : " + timer.purge()); } }
兩種狀況看區別
首次計劃執行的時間早於當前的時間 任務執行所需時間超出任務的執行週期間隔
首次計劃執行的時間早於當前的時間
1.schedule方法 「fixed-delay」,若是第一次執行時間被delay了, 隨後的執行時間按照上一次實際執行完成的時間點進行計算 2.scheduleAtFixedRate方法 「fixed-rate」,若是第一次執行時間被delay了, 隨後的執行時間按照上一次開始的時間點進行計算, 而且爲了遇上進度會屢次執行任務,所以TimerTask中的執行體須要考慮同步
代碼演示
package com.myimooc.timer; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Timer; import java.util.TimerTask; /** * schedule和scheduleAtFixedRate的區別 測試類 * Created by ChangComputer on 2017/5/24. */ public class DifferenceTest { public static void main(String[] args){ // 定義時間格式 final SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 獲取當前的具體時間 Calendar calendar = Calendar.getInstance(); System.out.println("Current time is : " + sf.format(calendar.getTime())); // 設置成6秒前的時間,若當前時間爲2016-12-28 00:00:06 // 那麼設置以後時間變成2016-12-28 00:00:00 calendar.add(Calendar.SECOND,-6); Timer timer = new Timer(); // 第一次執行時間爲6秒前,以後每隔兩秒鐘執行一次 //timer.schedule(new TimerTask() { timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { // 打印當前的計劃執行時間 System.out.println("Schedule exec time is : " + sf.format(scheduledExecutionTime())); System.out.println("Task is being executed!"); } }, calendar.getTime(), 2000); } }
任務執行所需時間超出任務的執行週期間隔
1. schedule方法 下一次執行時間相對於上一次實際執行完成的時間點,所以執行時間會不斷延後 2.scheduleAtFixedRate方法 下一次執行時間相對於上一次開始的時間點,所以執行時間通常不會延後,所以存在併發性
代碼演示
package com.myimooc.timer; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Timer; import java.util.TimerTask; /** * schedule和scheduleAtFixedRate的區別 測試類 * Created by ChangComputer on 2017/5/24. */ public class DifferenceTwoTest { public static void main(String[] args){ // 定義時間格式 final SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 獲取當前的具體時間 Calendar calendar = Calendar.getInstance(); System.out.println("Current time is : " + sf.format(calendar.getTime())); Timer timer = new Timer(); //timer.schedule(new TimerTask() { timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { try { Thread.sleep(3000L); } catch (InterruptedException e) { e.printStackTrace(); } // 打印最近一次的計劃執行時間 System.out.println("Schedule exec time is : " + sf.format(scheduledExecutionTime())); System.out.println("Task is being executed!"); } }, calendar.getTime(), 2000); } }
主要內容
經過模擬兩個機器人的定時行爲來把前面所學的主要函數給結合起來,讓你們加深對這些函數的理解
實現兩個機器人
第一個機器人會隔兩秒打印最近一次計劃的時間、執行內容 第二個機器人會模擬往桶裏倒水,直到桶裏的水滿爲止
灌水機器人的執行流程
跳舞機器人的執行流程
代碼演示
1.建立跳舞機器人
package com.myimooc.timer; import java.text.SimpleDateFormat; import java.util.TimerTask; /** * 跳舞機器人 * Created by ChangComputer on 2017/5/24. */ public class DancingRobot extends TimerTask{ /** * 任務執行 * */ @Override public void run() { // 獲取最近的一次任務執行的時間並將其格式化 SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.print("Schduled exec time is : " + sf.format(scheduledExecutionTime())); System.out.println("Dancing happily!"); } }
2.建立灌水機器人
package com.myimooc.timer; import java.util.Timer; import java.util.TimerTask; /** * 灌水機器人 * Created by ChangComputer on 2017/5/24. */ public class WaterRobot extends TimerTask{ private Timer timer; // 桶容量,最大容量爲5 private Integer bucketCapacity = 0; public WaterRobot(Timer timer){ this.timer = timer; } @Override public void run() { // 灌水直至桶滿爲止 if (this.bucketCapacity < 5) { System.out.println("Add 1L water into the bucket!"); bucketCapacity++; }else{ System.out.println("The number of canceled task in timer is : " + timer.purge()); // 水滿以後就中止執行 cancel(); System.out.println("The waterRobot has been aborted"); System.out.println("The number of canceled task in timer is : " + timer.purge()); System.out.println("Current water is : " + bucketCapacity); // 等待兩秒鐘,終止timer裏面的全部內容 try { Thread.sleep(2000L); } catch (InterruptedException e) { e.printStackTrace(); } timer.cancel(); } } }
3.建立執行類
package com.myimooc.timer; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Timer; /** * 機器人執行類 * Created by ChangComputer on 2017/5/24. */ public class RobotExecutor { public static void main(String[] args){ Timer timer = new Timer(); // 獲取當前時間 Calendar calendar = Calendar.getInstance(); SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current time is : " + sf.format(calendar.getTime())); DancingRobot dancingRobot = new DancingRobot(); WaterRobot waterRobot = new WaterRobot(timer); timer.schedule(dancingRobot,calendar.getTime(),2000L); timer.scheduleAtFixedRate(waterRobot,calendar.getTime(),1000L); } }
Timer天生的兩種缺陷
管理併發任務的缺陷
Timer有且僅有一個線程去執行定時任務,若是存在多個任務,且任務時間過長,會致使執行效果與預期不符
當任務拋出異常時的缺陷
若是TimerTask拋出RuntimeException,Timer會中止全部任務的運行
Timer的使用禁區
對時效性要求較高的多任務併發做業 對複雜任務的調度