1. 程式人生 > >Java定時任務排程工具Timer詳解

Java定時任務排程工具Timer詳解

做專案很多時候會用到定時任務,比如在深夜,流量較小的時候,做一些統計工作。早上定時傳送郵件,更新資料庫等。

這裡可以用Java的Timer或執行緒池實現。

Timer可以實現,不過Timer存在一些問題。他起一個單執行緒,如果有異常產生,執行緒將退出,整個定時任務就失敗。

Timer定時任務原理基本理解:單執行緒 + 最小堆 + 不斷輪詢

Timer有四種用法

四種用法,通過其引數名稱也可以瞭解到具體含義,下面舉例子來實現其功能:

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.SimpleTimeZone;
import java.util.TimerTask;

public class MyTimerTask extends TimerTask {

    private String name;
    private Integer count= 0;
    public MyTimerTask(String inputName){
        name=inputName;
    }
    //建立MyTimerTask類,實線其run方法
    @Override
    public void run(){
        if(count<3){
            Calendar calendar =Calendar.getInstance();
            SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            System.out.println("Current exec time is :"+sf.format(calendar.getTime()));
            System.out.println("Current name is:"+name);
            count++;
        }
        else {
            //結束
            cancel();
            System.out.println("The task is cancel");
        }
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

下面具體呼叫task幾種用法,可以執行檢視效果,具體實現功能在註釋中有介紹。 

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");
       
        Calendar calendar =Calendar.getInstance();
        SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current exec time is :"+sf.format(calendar.getTime()));

        // 這裡獲得3s後的時間
        calendar.add(Calendar.SECOND,3);
        //用法1: 1.到達指定時間時候或者超過time時間,執行且執行一次task任務
        myTimerTask.setName("schedue1");
        timer.schedule(myTimerTask,calendar.getTime());

        //用法2:2.指定達到該定時時候首次執行task,之後間隔為period毫秒執行一次
        myTimerTask.setName("schedule2");
        timer.schedule(myTimerTask,calendar.getTime(),2000);

        //用法3:3.delay表示執行任務前的時間,執行一次task
        myTimerTask.setName("schedule3");
        timer.schedule(myTimerTask,1000);

        //用法4:4.delay表示執行任務前的時間,執行一次task的時間間隔,類似第二種用法
        myTimerTask.setName("schedule4");
        timer.schedule(myTimerTask,1000,3000);

        //delay表示執行任務前的時間,執行一次task的時間間隔,類似第二種用法
        myTimerTask.setName("scheduleAtFixedRate1");
        //scheduleAtFixedRate用法和schedule用法類似,兩種,分別類似2和4兩種用法
        timer.scheduleAtFixedRate(myTimerTask,calendar.getTime(),3000);

    }
}

cancel()用在具體MyTaskTimer裡,終止的是其中具體事例的task,如果直接呼叫timer裡面的timer.cancel()則終止了所有的task。

這裡也可以將MyTaskTimer寫成內部類,就不用寫兩個類了。

scheduleAtFixedRate和schedule的區別

具體場景 schedule scheduleAtFixedRate
1、首次計劃執行時間早於當前時間 按照上一次實際執行完成的時間點來進行計算 按照上一次開始的時間點進行計算,並且為了趕上進度會多次執行任務,在TimerTask的執行中需要考慮同步
2、任務執行所需時間超出任務執行週期間隔 下一次執行時間相對於上一次實際執行完成的時間點,執行時間不斷延後 下一次執行時間相對於上一次開始的時間點,執行時間一般不會延後,因此存在併發性

Timer缺陷和使用禁區

1、在管理併發任務時候的缺陷:

Timer僅有一個執行緒去執行定時任務,如果存在多個任務,且任務時間比較長,則會產生和預期效果不符的情況。

2、處理丟擲異常時候的缺陷:

如果TimeTask丟擲RuntimeException,Timer就會停止所有任務的執行。

根據其缺陷,我們在使用時候注意,以下情況就不用Timer了,需要用到Quartz:

1、對時效性要求較高的多工併發作業

2、對複雜的任務的排程