1. 程式人生 > >Java定時任務排程工具詳解之Timer篇(初級)

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);