最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java定時任務(wù):利用java Timer類實(shí)現(xiàn)定時執(zhí)行任務(wù)的功能

 更新時間:2016年11月15日 15:08:00   作者:51kata  
本篇文章主要介紹了利用java Timer類實(shí)現(xiàn)定時執(zhí)行任務(wù)的功能,具有一定的參考價值,有需要的可以了解一下。

一、概述

在java中實(shí)現(xiàn)定時執(zhí)行任務(wù)的功能,主要用到兩個類,Timer和TimerTask類。其中Timer是用來在一個后臺線程按指定的計劃來執(zhí)行指定的任務(wù)。

TimerTask一個抽象類,它的子類代表一個可以被Timer計劃的任務(wù),具體要執(zhí)行的代碼寫在TimerTask需要被實(shí)現(xiàn)的run方法中。

二、先看一個最簡單的例子

我們通過代碼來說明

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerDemo {
  public static String getCurrentTime() {
    Date date = new Date();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    return sdf.format(date);
  }

  public static void main(String[] args) throws InterruptedException {
    System.out.println("main start:"+getCurrentTime());
    startTimer();
    Thread.sleep(1000*5); //休眠5秒
    System.out.println("main  end:"+getCurrentTime());
  }

  public static void startTimer(){
    TimerTask task = new TimerTask() {
      @Override
      public void run() {
        System.out.println("task  run:"+getCurrentTime());
      }
    };
    Timer timer = new Timer();
    timer.schedule(task, 0);
  }
}

為了便于通過打印觀察信息,我們在main方法中加了些打印信息,并調(diào)用Thread.sleep讓主線程休眠一下。另外在類中增加了一個獲取當(dāng)前日期的getCurrentTime方法。

上面的代碼,在startTimer方法中,先創(chuàng)建了一個TimerTask對象(將要被定時器執(zhí)行的任務(wù)),然后創(chuàng)建了一個Timer對象,然后調(diào)用Timer類的schedule方法。Timer類有多個帶不同參數(shù)的schedule方法。這里用到的是: 

public void schedule(TimerTask task, long delay)

該方法的含義是,表示定時器將延遲delay(毫秒)時間后,執(zhí)行task任務(wù)。如果delay為負(fù)數(shù)或0,則任務(wù)會被立即進(jìn)行。而且是一次性的執(zhí)行任務(wù),后續(xù)不會重復(fù)(或定時)執(zhí)行該任務(wù)。

對于Timer類,還提供一個同樣功能的方法,如下: 

public void schedule(TimerTask task, Date time)

該方法與上面方法的區(qū)別是,上面方法是指定延期一段時間執(zhí)行,這個方法是指定在某個具體的時間點(diǎn)執(zhí)行。注意,如果系統(tǒng)的當(dāng)前時間已經(jīng)超過了參數(shù)time指定的時間,該任務(wù)會被立即執(zhí)行。

當(dāng)運(yùn)行上面代碼時,我們發(fā)現(xiàn)程序立即打印類似如下的2條信息:

main start:2016-01-13 22:23:18
task   run:2016-01-13 22:23:18

因?yàn)槲覀冞@里給schedule方法傳遞的delay參數(shù)值為0,所以任務(wù)會被立即執(zhí)行,所以兩個語句打印出來的時間是一樣的,這是應(yīng)該的。大家可以自己改變傳入的delay值來看輸出信息的變化。再過大約5秒(即sleep的時間)后,繼續(xù)打印了1條信息:

main   end:2016-01-13 22:23:23

打印信息的時間與上面語句差了5秒,與sleep設(shè)置的一致,也是很合理的。

但我們會發(fā)現(xiàn)一個很有趣的現(xiàn)象,會發(fā)現(xiàn)該進(jìn)程不會退出,這時main主線程已經(jīng)結(jié)束了,這說明定時器把任務(wù)完成后,即使后面沒有待等待執(zhí)行的任務(wù)了,定時器中創(chuàng)建的后臺線程也不會立即退出。查看了相關(guān)的java doc文檔,解釋說定時器線程不會主動退出,需要等待垃圾回收,但java的待垃圾回收是無法通過代碼自己控制的,而是由虛擬機(jī)控制的。

研究了下,發(fā)現(xiàn)在創(chuàng)建Timer對象,及執(zhí)行Timer timer = new Timer(); 語句時,定時器線程就會被創(chuàng)建。也就是說即使上面代碼沒有timer.schedule(task, 0);這個語句,程序也不會退出。感覺這個挺不合理的。再次研究了下Timer類的源代碼,發(fā)現(xiàn)其還有一個帶布爾參數(shù)的構(gòu)造函數(shù):

public Timer(boolean isDaemon)

從參數(shù)名就可以看出,如果參數(shù)值為true時,則Timer創(chuàng)建的定時器線程為守護(hù)線程。守護(hù)線程的含義是,當(dāng)java進(jìn)程中所有的工作線程都退出后,守護(hù)線程就自動退出了。

這時我們只要把上面例子中的創(chuàng)建Timer對象的代碼改為:Timer timer = new Timer(true);

發(fā)現(xiàn)運(yùn)行程序后,等main線程(main線程不是守護(hù)線程,是工作線程)結(jié)束后,程序會退出,也就是說定時器線程也退出了,說明加上參數(shù)true后,創(chuàng)建的它是守護(hù)線程了。

但問題是,在真正的應(yīng)用場景中,有很多工作線程在運(yùn)行,程序不會隨便退出。那如果要想定時器能立即退出或關(guān)閉,該怎么辦呢?這個我們下面介紹。

三、定時器的退出

Timer類提供了一個cancel方法可以取消定時器。調(diào)用cancel方法會終止此計時器,丟棄所有當(dāng)前已安排的任務(wù)。這不會干擾當(dāng)前正在執(zhí)行的任務(wù)(如果存在)。一旦終止了計時器,那么它的執(zhí)行線程也會終止,并且無法根據(jù)它安排更多的任務(wù)。

注意,在此計時器調(diào)用的計時器任務(wù)的 run 方法內(nèi)調(diào)用此方法,就可以絕對確保正在執(zhí)行的任務(wù)是此計時器所執(zhí)行的最后一個任務(wù)??梢灾貜?fù)調(diào)用此方法;但是第二次和后續(xù)調(diào)用無效。

我們再看一個例子代碼:

 import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerDemo {
  public static String getCurrentTime() {
    Date date = new Date();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    return sdf.format(date);
  }

  public static void main(String[] args) throws InterruptedException {
    System.out.println("main start:"+getCurrentTime());
    Timer timer = startTimer();
    Thread.sleep(1000*5); //休眠5秒
    System.out.println("main  end:"+getCurrentTime());
    timer.cancel();
  }

  public static Timer startTimer(){
    TimerTask task = new TimerTask() {
      @Override
      public void run() {
        System.out.println("task  run:"+getCurrentTime());
      }
    };
    Timer timer = new Timer();
    timer.schedule(task, 0);
    return timer;
  }
}

運(yùn)行程序,跟上面一個例子的輸出情況完全一樣。區(qū)別是,當(dāng)main方法結(jié)束后。進(jìn)程會主動退出,也就是說定時器線程已經(jīng)關(guān)閉了。

因?yàn)槲覀冊趍ain方法中調(diào)用了cancel方法。 注意,如果不是在TimerTask的run方法中調(diào)用cancel方法一定要注意,一定要確保希望執(zhí)行的任務(wù)已經(jīng)開始執(zhí)行或執(zhí)行完畢,否則如果任務(wù)還未開始執(zhí)行。就調(diào)用cancel,則所有任務(wù)都不會被執(zhí)行了。比如上面的代碼,

比如上面的代碼,如果我們不在main方法中調(diào)用cancel方法,而是在startTimer方法中 timer.schedule(task, 0); 語句后加上timer.cancel();語句,運(yùn)行后會發(fā)現(xiàn),定時器任務(wù)不會被執(zhí)行,因?yàn)檫€未來得及執(zhí)行就被取消中止了。

四、定時執(zhí)行任務(wù)

上面的例子,我們介紹的是一次性任務(wù),也就是定時器時間到了,執(zhí)行完任務(wù),后面不會再重復(fù)執(zhí)行。在實(shí)際的應(yīng)用中,有很多場景需要定時重復(fù)的執(zhí)行同一個任務(wù)。這也分兩種情況,一是每隔一段時間就執(zhí)行任務(wù),二是每天(或每周、每月等)的固定某個(或某幾個)時間點(diǎn)來執(zhí)行任務(wù)。

我們先來看第一種情況,實(shí)現(xiàn)每隔10秒執(zhí)行同一任務(wù)的例子。代碼如下:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerDemo {
  public static String getCurrentTime() {
    Date date = new Date();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    return sdf.format(date);
  }

  public static void main(String[] args) throws InterruptedException {
    System.out.println("main start:"+getCurrentTime());
    startTimer();
  }

  public static void startTimer(){
    TimerTask task = new TimerTask() {
      @Override
      public void run() {
        System.out.println("task  run:"+getCurrentTime());
        try {
          Thread.sleep(1000*3);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    };
    Timer timer = new Timer();
    timer.schedule(task, 1000*5,1000*10);
  }
}

執(zhí)行上述程序,輸出信息如下(因?yàn)槎〞r器沒有停止,重復(fù)執(zhí)行任務(wù),會不斷輸出,這里只拷貝了前面的一些輸出)

main start:2016-01-14 08:41:14
task   run:2016-01-14 08:41:19
task   run:2016-01-14 08:41:29
task   run:2016-01-14 08:41:39
task   run:2016-01-14 08:41:49
task   run:2016-01-14 08:42:00
task   run:2016-01-14 08:42:10
task   run:2016-01-14 08:42:20
task   run:2016-01-14 08:42:30
task   run:2016-01-14 08:42:40

在上面的代碼中,我們調(diào)用了 timer.schedule(task, 1000*5,1000*10); 這個含義是該任務(wù)延遲5秒后執(zhí)行,然后會每隔10秒重復(fù)執(zhí)行。我們觀察輸出信息中打印的時間,是與預(yù)期一樣的。 另外可以看出,間隔是以任務(wù)開始執(zhí)行時間為起點(diǎn)算的,也就是并不是任務(wù)執(zhí)行完成后再等待10秒。

Timer類有兩個方法可以實(shí)現(xiàn)這樣的功能,如下:

public void schedule(TimerTask task, long delay, long period)

public void schedule(TimerTask task, Date firstTime, long period)

我們上面代碼用的是第一個方法。兩個方法區(qū)別在于第一次執(zhí)行的時間,第一個方法是在指定延期一段時間(單位為毫秒)后執(zhí)行;第二個方法是在指定的時間點(diǎn)執(zhí)行。

這時我們考慮如下場景,如果某個任務(wù)的執(zhí)行耗時超過了下次等待時間,會出現(xiàn)什么情況呢? 我們還是通過代碼來看:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerDemo {
  public static String getCurrentTime() {
    Date date = new Date();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    return sdf.format(date);
  }

  public static void main(String[] args) throws InterruptedException {
    System.out.println("main start:"+getCurrentTime());
    startTimer();
  }

  public static void startTimer(){
    TimerTask task = new TimerTask() {
      @Override
      public void run() {
        System.out.println("task begin:"+getCurrentTime());
        try {
          Thread.sleep(1000*10);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        System.out.println("task  end:"+getCurrentTime());
      }
    };
    Timer timer = new Timer();
    timer.schedule(task, 1000*5,1000*5);
  }
}

與前面代碼相比,我們只改了2處代碼和修改了下打印,一是將run方法中的sleep改為了10秒,二是將任務(wù)的執(zhí)行周期改為5秒。也就說任務(wù)的執(zhí)行耗時超過了任務(wù)重復(fù)執(zhí)行的間隔。運(yùn)行程序,前面的輸出如下:

main start:2016-01-14 09:03:51
task begin:2016-01-14 09:03:56
task   end:2016-01-14 09:04:06
task begin:2016-01-14 09:04:06
task   end:2016-01-14 09:04:16
task begin:2016-01-14 09:04:16
task   end:2016-01-14 09:04:26
task begin:2016-01-14 09:04:26
task   end:2016-01-14 09:04:36
task begin:2016-01-14 09:04:36
task   end:2016-01-14 09:04:46
task begin:2016-01-14 09:04:46
task   end:2016-01-14 09:04:56

可以看出,每個任務(wù)執(zhí)行完成后,會立即執(zhí)行下一個任務(wù)。因?yàn)閺娜蝿?wù)開始執(zhí)行到任務(wù)完成的耗時已經(jīng)超過了任務(wù)重復(fù)的間隔時間,所以會重復(fù)執(zhí)行。

五、定時執(zhí)行任務(wù)(重復(fù)固定時間點(diǎn)執(zhí)行)

我們來實(shí)現(xiàn)這樣一個功能,每天的凌晨1點(diǎn)定時執(zhí)行一個任務(wù),這在很多系統(tǒng)中都有這種功能,比如在這個任務(wù)中完成數(shù)據(jù)備份、數(shù)據(jù)統(tǒng)計等耗時、耗資源較多的任務(wù)。代碼如下:

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerDemo {
  public static String getCurrentTime() {
    Date date = new Date();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    return sdf.format(date);
  }

  public static void main(String[] args) throws InterruptedException {
    System.out.println("main start:" + getCurrentTime());
    startTimer();
  }

  public static void startTimer() {
    TimerTask task = new TimerTask() {
      @Override
      public void run() {
        System.out.println("task begin:" + getCurrentTime());
        try {
          Thread.sleep(1000 * 20);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        System.out.println("task  end:" + getCurrentTime());
      }
    };
    Timer timer = new Timer();
    timer.schedule(task, buildTime(), 1000 * 60 * 60 * 24);
  }

  private static Date buildTime() {
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.HOUR_OF_DAY, 1);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    Date time = calendar.getTime();
    if (time.before(new Date())) {
      //若果當(dāng)前時間已經(jīng)是凌晨1點(diǎn)后,需要往后加1天,否則任務(wù)會立即執(zhí)行。
      //很多系統(tǒng)往往系統(tǒng)啟動時就需要立即執(zhí)行一次任務(wù),但下面又需要每天凌晨1點(diǎn)執(zhí)行,怎么辦呢?
      //很簡單,就在系統(tǒng)初始化話時單獨(dú)執(zhí)行一次任務(wù)(不需要用定時器,只是執(zhí)行那段任務(wù)的代碼)
      time = addDay(time, 1);
    }
    return time;
  }

  private static Date addDay(Date date, int days) {
    Calendar startDT = Calendar.getInstance();
    startDT.setTime(date);
    startDT.add(Calendar.DAY_OF_MONTH, days);
    return startDT.getTime();
  }

}

因?yàn)槭情g隔24小時執(zhí)行,沒法等待觀察輸出。

六、小結(jié)

本文介紹了利用java Timer類如何執(zhí)行定時任務(wù)的機(jī)制。可以看出,還是有許多需要注意的方法。 本文中介紹的例子,每個定時器只對應(yīng)一個任務(wù)。

本文介紹的內(nèi)容可以滿足大部分應(yīng)用場景了,但還有一些問題,比如對于一個定時器包括多個任務(wù)?定時器取消后能否再次添加任務(wù)?Timer類中還有哪些方法可用? 這些問題,我們再后面的博文中介紹。

原文鏈接:http://www.cnblogs.com/51kata/p/5128745.html

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 淺談mybatis如何半自動化解耦(推薦)

    淺談mybatis如何半自動化解耦(推薦)

    這篇文章主要介紹了淺談mybatis如何半自動化解耦,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • Java常用工具類—集合排序

    Java常用工具類—集合排序

    這篇文章主要介紹了Java集合排序,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Springboot+redis+Vue實(shí)現(xiàn)秒殺的項(xiàng)目實(shí)踐

    Springboot+redis+Vue實(shí)現(xiàn)秒殺的項(xiàng)目實(shí)踐

    本文主要介紹了Springboot+redis+Vue實(shí)現(xiàn)秒殺的項(xiàng)目實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • java類型生命周期的詳細(xì)解析

    java類型生命周期的詳細(xì)解析

    以下是對java中的類型生命周期進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下
    2013-08-08
  • JAVA調(diào)用JavaScript的方法示例

    JAVA調(diào)用JavaScript的方法示例

    本文主要介紹了JAVA調(diào)用JavaScript的方法示例,主要介紹了兩種方式,一種是使用Java的ScriptEngine接口,另一種是使用Java的URLConnection類來獲取JS文件,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • 關(guān)于Java中避免空指針的方法

    關(guān)于Java中避免空指針的方法

    這篇文章主要介紹了關(guān)于Java中避免空指針的方法,空指針異常就是我們在對空對象進(jìn)行的任何操作都會報空指針異常,所謂的指針,就是java中的對象的引用,比如String?s;這個就是指針,需要的朋友可以參考下
    2023-07-07
  • SpringBoot生產(chǎn)環(huán)境和測試環(huán)境配置分離的教程詳解

    SpringBoot生產(chǎn)環(huán)境和測試環(huán)境配置分離的教程詳解

    這篇文章主要介紹了SpringBoot生產(chǎn)環(huán)境和測試環(huán)境配置分離的教程詳解,需要的朋友可以參考下
    2020-08-08
  • 深入淺析Spring-boot-starter常用依賴模塊

    深入淺析Spring-boot-starter常用依賴模塊

    這篇文章主要介紹了Spring-boot-starter常用依賴模塊及spring boot的兩大優(yōu)點(diǎn),需要的朋友可以參考下
    2018-01-01
  • Go Java算法之解碼方法示例詳解

    Go Java算法之解碼方法示例詳解

    這篇文章主要為大家介紹了Go Java算法之解碼方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Spring獲取當(dāng)前類在容器中的beanname實(shí)現(xiàn)思路

    Spring獲取當(dāng)前類在容器中的beanname實(shí)現(xiàn)思路

    這篇文章主要介紹了Spring獲取當(dāng)前類在容器中的beanname,實(shí)現(xiàn)思路只需繼承BeanNameAware接口,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07

最新評論

合川市| 营口市| 潼南县| 乐都县| 涿州市| 陆良县| 洮南市| 博白县| 冀州市| 南木林县| 南投县| 济阳县| 罗平县| 忻城县| 大荔县| 长岭县| 大同县| 天台县| 微博| 蒙城县| 宽甸| 江阴市| 民权县| 卫辉市| 莱西市| 河西区| 商洛市| 潼关县| 冕宁县| 宣城市| 青铜峡市| 柘荣县| 龙州县| 庆阳市| 邵阳县| 普兰县| 卫辉市| 曲水县| 南部县| 凤山县| 绥德县|