Java定時任務排程工具詳解之Timer篇(初級)
一.Timer簡介
定時任務的基本概念,Timer的函式,綜合運用和缺陷
基於給定的時間點,給定的時間間隔或者給定的執行次數自動執行的任務。
Timer 和Quartz
Timer:
出身:由jdk提供,呼叫方式簡單粗暴;
能力:Timer能完成一些簡單的定時任務,如需要指定某個具體時間執行任務的話,Timer就能輕鬆實現。
Quartz
出身:需要引入架包
能力:能完成比較複雜的功能需求
底層機制:能夠實現多個執行執行緒
定義:有且僅有一個後臺執行緒對多個業務執行緒進行定時定頻率的排程
Timer(後臺執行執行緒)對TimerTask(業務執行緒)的定時呼叫
通過程式來講解Timer,開啟Eclipse
建立java工程MyTimerProject
建立包和class檔案
MyTimerTask.java
package com.vishuo.timer;
import java.util.TimerTask;
public class MyTimerTask extends TimerTask{
private String name;
public MyTimerTask(String inputName){
name=inputName;
}
@Override
public void run() {
// TODO Auto-generated method stub
//列印當前name的內容
System.out.println("Current exec name is:"+name);
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName (String name) {
this.name = name;
}
}
建立MyTimer類
package com.vishuo.timer;
import java.util.Timer;
public class MyTimer {
public static void main(String[] args) {
//1.建立一個timer例項
Timer timer = new Timer();
//2.建立一個MyTimerTask例項
MyTimerTask myTimerTask = new MyTimerTask("No.1");
//3.通過timer定時定頻率呼叫myTimerTask的業務邏輯
//即第一次執行是在當前時間的兩秒之後,之後每隔一秒鐘執行一次
timer.schedule(myTimerTask, 2000L,1000L);
}
}
二.timer定時函式的用法
schedule的四種用法
第一種用法:
schedule(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的兩種用法
第一種用法:
scheduleAtFixedRate(task,time,period)
引數
task—所要安排的任務
time—首次執行任務前的時間
period—執行一次task的時間間隔,單位是毫秒
作用:時間等於或超過time時首次執行task
之後每隔period毫秒重複執行一次task
scheduleAtFixedRate(task,delay,period)
引數
task—所要安排的任務
delay—執行任務前的延遲時間,單位是毫秒
period—執行一次task的時間間隔,單位是毫秒
作用:等待delay毫秒後首次執行task
之後沒隔period毫秒重複執行一次task
全部方法程式碼示例:
MyTimerTask類
package com.vishuo.timer;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimerTask;
public class MyTimerTask extends TimerTask{
private String name;
public MyTimerTask(String inputName){
name=inputName;
}
@Override
public void run() {
// TODO Auto-generated method stub
//以yyyy-MM-dd HH:mm:ss的格式列印當前執行時間
//如2016-11-11 00:00:00
Calendar calendar = Calendar.getInstance();
SimpleDateFormat sf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Curren exec time is:"+sf.format(calendar.getTime()));
//列印當前name的內容
System.out.println("Current exec name is:"+name);
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
}
MyTimer類
package com.vishuo.timer;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Timer;
public class MyTimer {
public static void main(String[] args) {
// 1.建立一個timer例項
Timer timer = new Timer();
// 2.建立一個MyTimerTask例項
MyTimerTask myTimerTask = new MyTimerTask("No.1");
// 3.通過timer定時定頻率呼叫myTimerTask的業務邏輯
//即第一次執行是在當前時間的兩秒之後,之後每隔一秒鐘執行一次
// timer.schedule(myTimerTask, 2000L,1000L);
/*
* 獲取當前時間,並設定成距離當前時間三秒之後的時間
* 如當前時間是2016-11-10 23:59:57
* 則設定後的時間則為2016-11-11 00:00:00
*/
Calendar calendar = Calendar.getInstance();
SimpleDateFormat sf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sf.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(),2000);
/*
* 3.等待delay毫秒後執行且僅執行一次task
* 如現在是2016-11-11 00:00:00
* 則在2016-11-11 00:00:00執行一次task:列印任務的名字
*/
// myTimerTask.setName("schedule3");
// timer.schedule(myTimerTask, 1000);
/*
* 4.等待delay毫秒後首次執行task
* 之後每隔period毫秒重複執行一次task
* 如現在是2016-11-11 00:00:00
* 則在2016-11-11 00:00:00第一次執行task:列印任務的名字
* 之後每隔兩秒執行一次task
*/
// myTimerTask.setName("schedule4");
// timer.schedule(myTimerTask, 3000,2000);
// —————————— scheduleAtFixedRate的用法 ——————————
/*
* 1.時間等於或超過time時首次執行task
* 之後沒隔period毫秒重複執行一次task
* 如在2016-11-11 00:00:00第一次執行task:列印任務名字
* 之後每隔兩秒執行一次task
*/
// myTimerTask.setName("scheduleAtFixedRate1");
// timer.scheduleAtFixedRate(myTimerTask, calendar.getTime(), 2000);
/*
* 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,3000, 2000);
}
}
三.其他重要函式
TimerTask的cancel(),scheduledExecutionTime()
cancel()
作用:取消當前TimerTask裡的任務
程式碼示例
修改MyTimerTask類,使程式執行三次後,結束任務。上面的MyTimer保持不變,依舊讓其執行
myTimerTask.setName("scheduleAtFixedRate2");
timer.scheduleAtFixedRate(myTimerTask,3000, 2000);
MyTimerTask類修改如下:
package com.vishuo.timer;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimerTask;
public class MyTimerTask extends TimerTask{
private String name;
private Integer count = 0;
public MyTimerTask(String inputName){
name=inputName;
}
@Override
public void run() {
// TODO Auto-generated method stub
if(count < 3){
//以yyyy-MM-dd HH:mm:ss的格式列印當前執行時間
//如2016-11-11 00:00:00
Calendar calendar = Calendar.getInstance();
SimpleDateFormat sf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Curren exec time is:"+sf.format(calendar.getTime()));
//列印當前name的內容
System.out.println("Current exec name is:"+name);
count ++;
}else{
cancel();
System.out.println("Task cancel!");
}
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
}
scheduledExecutionTime()
作用:返回次任務最近實際執行的已安排執行的時間
返回值:最近發生此任務執行安排的時間,為long型
package com.vishuo.timer;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Timer;
public class MyTimer {
public static void main(String[] args) {
// 1.建立一個timer例項
Timer timer = new Timer();
// 2.建立一個MyTimerTask例項
MyTimerTask myTimerTask = new MyTimerTask("No.1");
// 3.通過timer定時定頻率呼叫myTimerTask的業務邏輯
//即第一次執行是在當前時間的兩秒之後,之後每隔一秒鐘執行一次
// timer.schedule(myTimerTask, 2000L,1000L);
/*
* 獲取當前時間,並設定成距離當前時間三秒之後的時間
* 如當前時間是2016-11-10 23:59:57
* 則設定後的時間則為2016-11-11 00:00:00
*/
Calendar calendar = Calendar.getInstance();
SimpleDateFormat sf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sf.format(calendar.getTime()));//獲取當前時間
calendar.add(Calendar.SECOND, 3);//獲取當前時間後三秒的時間
/*
* scheduledExecutionTime程式碼示例
*/
myTimerTask.setName("schedule4");
timer.schedule(myTimerTask, 3000);
System.out.println("scheduled time is"+ sf.format(myTimerTask.scheduledExecutionTime()));
}
}
Timer的cancel(),purge()
cancel()
作用:終止此計時器,丟棄所有當前已安排的任務
程式碼示例:
新增CancelTest類
package com.vishuo.timer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
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 sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("start time is:"+sf.format(startTime));
//task1首次執行是距離現在時間3秒後執行,之後每隔2秒執行一次;
//task2首次執行是距離現在時間1秒後執行,之後每隔2秒執行一次;
timer.schedule(task1, 3000,2000);
timer.schedule(task2, 1000,2000);
//休眠5秒
Thread.sleep(5000);
//獲取當前的執行時間並列印
Date cancelTime = new Date();
System.out.println("cancel time is :"+sf.format(cancelTime));
//取消所有任務
timer.cancel();
System.out.println("Tasks all canceled!");
}
}
purge()
作用:從此計時器的任務佇列中移除所有已取消的任務
返回值:從佇列中移除的任務數
演示程式碼:修改CancelTest類
package com.vishuo.timer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
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 sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("start time is:" + sf.format(startTime));
// task1首次執行是距離現在時間3秒後執行,之後每隔2秒執行一次;
// task2首次執行是距離現在時間1秒後執行,之後每隔2秒執行一次;
timer.schedule(task1, 3000, 2000);
timer.schedule(task2, 1000, 2000);
System.out.println("current canceled task number is:"+timer.purge());
// 休眠5秒
// Thread.sleep(5000);
//休眠2秒
Thread.sleep(2000);
// 獲取當前的執行時間並列印
Date cancelTime = new Date();
System.out.println("cancel time is :" + sf.format(cancelTime));
// 取消所有任務
// timer.cancel();
// System.out.println("Tasks all canceled!");
//取消task2
task2.cancel();
System.out.println("current canceled task number is:"+timer.purge());
}
}
四.schedule和scheduleAtFixedRate的區別
兩種情況看區別
1.首次計劃執行的時間早於當前的時間
schedule方法:“fixed-delay”;如果第一次執行時間被delay了,隨後的執行時間按照上一次實際執行完成的時間點進行計算。
示例程式碼:
新建DifferenceTest類
package com.vishuo.timer;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;
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() {
@Override
public void run() {
// TODO Auto-generated method stub
// 列印當前的計劃執行時間
System.out.println("Scheduled exec time is :" + sf.format(scheduledExecutionTime()));
System.out.println("Task is being executed!");
}
}, calendar.getTime(), 2000);
}
}
scheduleAtFiexedRate方法
“fixed-rate”:如果第一次執行時間被delay了,隨後的執行時間按照上一次開始的時間點進行計算,並且為了趕上進度會多次執行任務,因此TimerTask中的執行體需要考慮同步
程式碼示例:
修改DifferenceTest類
// 第一次執行時間為6秒前,之後每隔兩秒鐘執行一次
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
// 列印當前的計劃執行時間
System.out.println("Scheduled exec time is :" + sf.format(scheduledExecutionTime()));
System.out.println("Task is being executed!");
}
}, calendar.getTime(), 2000);
2.任務執行所需時間超出任務的執行週期間隔
schedule方法
下一次執行時間相對於上一次實際執行完成的時間點,因此執行時間會不斷延後
程式碼示例:
修改DifferenceTest類
package com.vishuo.timer;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;
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();
timer.schedule(new TimerTask() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO Auto-generated method stub
// 列印當前的計劃執行時間
System.out.println("Scheduled exec time is :" + sf.format(scheduledExecutionTime()));
System.out.println("Task is being executed!");
}
}, calendar.getTime(), 2000);
}
}
scheduleAtFixedRate方法
下一次執行時間相對於上一次開始的時間點,因此執行時間一般不會延後,因此存在併發性
程式碼示例:修改DifferenceTest類
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO Auto-generated method stub
// 列印當前的計劃執行時間
System.out.println("Scheduled exec time is :" + sf.format(scheduledExecutionTime()));
System.out.println("Task is being executed!");
}
}, calendar.getTime(), 2000);