欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java?Timer使用講解

 更新時間:2022年11月02日 10:23:48   作者:UnicornLien  
Timer是一種工具,線程用其安排以后在后臺線程中執(zhí)行的任務(wù)。可安排任務(wù)執(zhí)行一次,或者定期重復(fù)執(zhí)行,這篇文章主要介紹了Java?Timer使用講解,需要的朋友可以參考下

Timer 詳解

Timer 和 TimerTask 用于在后臺線程中調(diào)度任務(wù)的 java.util 類。 TimerTask 負責任務(wù)的執(zhí)行, Timer 負責任務(wù)的調(diào)度。

定時功能

Timer 提供了三種定時模式:

fixed delay
fixed rate

java.util包下提供了對定時任務(wù)的支持,涉及2個類:

  1. Timer:定時器類
  2. TimerTask:任務(wù)抽象類

使用該定時任務(wù)我們需要繼承TimerTask抽象類,覆蓋run方法編寫任務(wù)執(zhí)行代碼,并利用Timer定時器對TimerTask進行調(diào)度。

編寫一個任務(wù):

TimerTask task = new TimerTask() {
    @Override
    public void run() {
        System.out.println(DateUtil.formatNow() + " " + Thread.currentThread().getName() + " task run ");
    }
};

接著使用Timer對TimerTask進行調(diào)度,Timer提供了多種方法,可分為一次性任務(wù)和可重復(fù)執(zhí)行任務(wù)。

一、一次性任務(wù)

一次性任務(wù)是指Timer執(zhí)行一次之后,該任務(wù)后續(xù)不再執(zhí)行。

一次性任務(wù)包括2個方法,如下:

  1. voidschedule(TimerTasktask,longdelay):延遲delay毫秒后執(zhí)行一次task
  2. voidschedule(TimerTasktask,Datetime):在指定時間time執(zhí)行一次task,如果time過期,將會立即執(zhí)行

二、可重復(fù)執(zhí)行任務(wù)

可重復(fù)執(zhí)行任務(wù)是指,任務(wù)允許按照設(shè)定的規(guī)則重復(fù)執(zhí)行。

可重復(fù)執(zhí)行任務(wù)共有4個方法,分為固定延時 schedule和固定速率 scheduleAtFixedRate:

  1. voidschedule(TimerTasktask,longdelay,longperiod):延遲delay毫秒后執(zhí)行task,之后每隔period毫秒執(zhí)行一次task
  2. voidschedule(TimerTasktask,DatefirstTime,longperiod):在指定時間time執(zhí)行一次task,之后每隔period毫秒執(zhí)行一次task
  3. voidscheduleAtFixedRate(TimerTasktask,longdelay,longperiod):延遲delay毫秒后執(zhí)行task,之后每隔period毫秒執(zhí)行一次task
  4. voidscheduleAtFixedRate(TimerTasktask,DatefirstTime,longperiod):在指定時間time執(zhí)行一次task,之后每隔period毫秒執(zhí)行一次task

示例1:schedule方法,延遲delay毫秒后執(zhí)行task,之后每隔period毫秒執(zhí)行一次task

System.out.println("啟動于:" + DateUtil.formatNow());
Timer timer = new Timer("timer");
timer.schedule(task, 1000, 2000);

輸出:

啟動于:2022-10-31 10:05:15
2022-10-31 10:05:16 timer task run 
2022-10-31 10:05:18 timer task run 
2022-10-31 10:05:20 timer task run

示例2:schedule在指定時間time執(zhí)行一次task,之后每隔period毫秒執(zhí)行一次task

System.out.println("啟動于:" + DateUtil.formatNow());
Timer timer = new Timer("timer");
timer.schedule(task, DateUtil.parse("2022-10-31 10:07:00", DateUtil.YYYY_MM_DD_HH24_MM_SS), 2000);

輸出:

啟動于:2022-10-31 10:06:39
2022-10-31 10:07:00 timer task run 
2022-10-31 10:07:02 timer task run 
2022-10-31 10:07:04 timer task run 

固定延時 schedule 和 固定速率 scheduleAtFixedRate 在正常情況下看起來功能基本是一致的,區(qū)別在于當任務(wù)耗時超出執(zhí)行時間間隔period,后續(xù)任務(wù)被延誤時,schedule和scheduleAtFixedRate的處理方式不同,后面介紹。

三、固定延時和固定速率區(qū)別(重點)

1. 介紹

由于Timer內(nèi)部僅維護一個線程來執(zhí)行所有任務(wù),所以當前一個任務(wù)耗時過長,可能會導(dǎo)致后一個任務(wù)的執(zhí)行被延誤。

出現(xiàn)任務(wù)延誤的情況下,固定延時 schedule和 固定速率 scheduleAtFixedRate 的區(qū)別就在于,schedule會順延,而scheduleAtFixedRate會把延誤任務(wù)立馬補上。

在網(wǎng)上看到幾個非常恰當?shù)睦樱N上來加深理解。

例1:

暑假到了老師給schedule和scheduleAtFixedRate兩個同學布置作業(yè)。

老師要求學生暑假每天寫2頁,30天后完成作業(yè)。

這兩個學生每天按時完成作業(yè),直到第10天,出了意外,兩個學生出去旅游花了5天時間,這5天時間里兩個人都沒有做作業(yè)。任務(wù)被拖延了。

這時候兩個學生采取的策略就不同了:

schedule重新安排了任務(wù)時間,旅游回來的第一天做第11天的任務(wù),第二天做第12天的任務(wù),最后完成任務(wù)花了35天。

scheduleAtFixedRate是個守時的學生,她總想按時完成老師的任務(wù),于是在旅游回來的第一天把之前5天欠下的任務(wù)以及第16天當天的任務(wù)全部完成了,之后還是按照老師的原安排完成作業(yè),最后完成任務(wù)花了30天。

例2:

固定速率就好比你今天加班到很晚,但是到了第二天還必須準點到公司上班,如果你一不小心加班到了第二天早上 9 點,你就連休息的時間都沒有了。

而固定時延的意思是你必須睡夠 8 個小時再過來上班,如果你加班到凌晨 6 點,那就可以下午過來上班了。

固定速率強調(diào)準點,固定時延強調(diào)間隔。

如果任務(wù)必須每天準點調(diào)度,那就應(yīng)該使用固定速率調(diào)度,并且要確保每個任務(wù)執(zhí)行時間不要太長,避免超過period間隔。

如果任務(wù)需要每隔幾分鐘跑一次,那就使用固定時延調(diào)度,它不是很在乎單個任務(wù)要跑多長時間。

我們來模擬一下這個情況。

首先,我們對TimerTask進行修改,讓它某一次任務(wù)產(chǎn)生大量耗時:

TimerTask task = new TimerTask() {
    private int i = 1;
    @Override
    public void run() {
        System.out.print(i + " " + DateUtil.formatNow() + " 開始執(zhí)行, ");
        if(i == 3) {
            ThreadUtil.sleep(11 * 1000);
        }
        System.out.println(DateUtil.formatNow() + " 結(jié)束");
        i++;
    }
};

該任務(wù)在執(zhí)行第3次時,將會休眠11秒,這將會導(dǎo)致延誤后續(xù)的任務(wù)。

2. 固定速率

示例:

Timer timer = new Timer("timer");
timer.scheduleAtFixedRate(task, 5000, 2000);

設(shè)定任務(wù)延遲5秒后執(zhí)行第1次任務(wù),之后每2秒執(zhí)行一次。

輸出:

啟動于:2022-10-31 15:51:24
1 2022-10-31 15:51:29 開始執(zhí)行, 2022-10-31 15:51:29 結(jié)束
2 2022-10-31 15:51:31 開始執(zhí)行, 2022-10-31 15:51:31 結(jié)束
3 2022-10-31 15:51:33 開始執(zhí)行, 2022-10-31 15:51:44 結(jié)束 *
4 2022-10-31 15:51:44 開始執(zhí)行, 2022-10-31 15:51:44 結(jié)束 *
5 2022-10-31 15:51:44 開始執(zhí)行, 2022-10-31 15:51:44 結(jié)束 *
6 2022-10-31 15:51:44 開始執(zhí)行, 2022-10-31 15:51:44 結(jié)束 *
7 2022-10-31 15:51:44 開始執(zhí)行, 2022-10-31 15:51:44 結(jié)束 *
8 2022-10-31 15:51:44 開始執(zhí)行, 2022-10-31 15:51:44 結(jié)束 *
9 2022-10-31 15:51:45 開始執(zhí)行, 2022-10-31 15:51:45 結(jié)束
10 2022-10-31 15:51:47 開始執(zhí)行, 2022-10-31 15:51:47 結(jié)束
11 2022-10-31 15:51:49 開始執(zhí)行, 2022-10-31 15:51:49 結(jié)束

如果不存在第3次耗時11秒的情況下,正常任務(wù)執(zhí)行時間應(yīng)該為:

啟動于:2022-10-31 15:51:24
1 2022-10-31 15:51:29 開始執(zhí)行, 2022-10-31 15:51:29 結(jié)束
2 2022-10-31 15:51:31 開始執(zhí)行, 2022-10-31 15:51:31 結(jié)束
3 2022-10-31 15:51:33 開始執(zhí)行, 2022-10-31 15:51:33 結(jié)束 *
4 2022-10-31 15:51:35 開始執(zhí)行, 2022-10-31 15:51:35 結(jié)束 *
5 2022-10-31 15:51:37 開始執(zhí)行, 2022-10-31 15:51:37 結(jié)束 *
6 2022-10-31 15:51:39 開始執(zhí)行, 2022-10-31 15:51:39 結(jié)束 *
7 2022-10-31 15:51:41 開始執(zhí)行, 2022-10-31 15:51:41 結(jié)束 *
8 2022-10-31 15:51:43 開始執(zhí)行, 2022-10-31 15:51:43 結(jié)束 *
9 2022-10-31 15:51:45 開始執(zhí)行, 2022-10-31 15:51:45 結(jié)束
10 2022-10-31 15:51:47 開始執(zhí)行, 2022-10-31 15:51:47 結(jié)束
11 2022-10-31 15:51:49 開始執(zhí)行, 2022-10-31 15:51:49 結(jié)束

但是在第3次執(zhí)行任務(wù)時因為執(zhí)行耗時11秒,第4次本該在15:51:35開始執(zhí)行并完成任務(wù),卻到了15:51:44才執(zhí)行完成,這11秒延誤了后續(xù)5個任務(wù)的正常執(zhí)行,因此在15:51:44時,scheduleAtFixedRate趕作業(yè)把延誤的5個任務(wù)一起執(zhí)行了。

最后趕上了原本的進度,第9個任務(wù)準時在15:51:45執(zhí)行。

3. 固定延時

示例:

Timer timer = new Timer("timer");
timer.schedule(task, 5000, 2000);

輸出:

啟動于:2022-10-31 15:56:59
1 2022-10-31 15:57:04 開始執(zhí)行, 2022-10-31 15:57:04 結(jié)束
2 2022-10-31 15:57:06 開始執(zhí)行, 2022-10-31 15:57:06 結(jié)束
3 2022-10-31 15:57:08 開始執(zhí)行, 2022-10-31 15:57:19 結(jié)束 *
4 2022-10-31 15:57:19 開始執(zhí)行, 2022-10-31 15:57:19 結(jié)束
5 2022-10-31 15:57:21 開始執(zhí)行, 2022-10-31 15:57:21 結(jié)束
6 2022-10-31 15:57:24 開始執(zhí)行, 2022-10-31 15:57:24 結(jié)束
7 2022-10-31 15:57:26 開始執(zhí)行, 2022-10-31 15:57:26 結(jié)束
8 2022-10-31 15:57:28 開始執(zhí)行, 2022-10-31 15:57:28 結(jié)束
9 2022-10-31 15:57:30 開始執(zhí)行, 2022-10-31 15:57:30 結(jié)束
10 2022-10-31 15:57:32 開始執(zhí)行, 2022-10-31 15:57:32 結(jié)束

如果不存在第3次耗時11秒的情況下,正常任務(wù)執(zhí)行時間應(yīng)該為:

啟動于:2022-10-31 15:56:59
1 2022-10-31 15:57:04 開始執(zhí)行, 2022-10-31 15:57:04 結(jié)束
2 2022-10-31 15:57:06 開始執(zhí)行, 2022-10-31 15:57:06 結(jié)束
3 2022-10-31 15:57:08 開始執(zhí)行, 2022-10-31 15:57:08 結(jié)束 *
4 2022-10-31 15:57:10 開始執(zhí)行, 2022-10-31 15:57:10 結(jié)束
5 2022-10-31 15:57:12 開始執(zhí)行, 2022-10-31 15:57:12 結(jié)束
6 2022-10-31 15:57:14 開始執(zhí)行, 2022-10-31 15:57:14 結(jié)束
7 2022-10-31 15:57:16 開始執(zhí)行, 2022-10-31 15:57:16 結(jié)束
8 2022-10-31 15:57:18 開始執(zhí)行, 2022-10-31 15:57:18 結(jié)束
9 2022-10-31 15:57:20 開始執(zhí)行, 2022-10-31 15:57:20 結(jié)束
10 2022-10-31 15:57:22 開始執(zhí)行, 2022-10-31 15:57:22 結(jié)束

使用schedule調(diào)度,第4次任務(wù)本該在15:57:10開始執(zhí)行,但由于耗時11秒直到15:57:19才開始。

而第3次任務(wù)實際是在19秒完成,完成后又在19秒立即執(zhí)行第4次,中間少了2秒間隔,第4次完成后接著開始2秒一次,變?yōu)榱藦?1秒開始執(zhí)行第5次。

和我原本的推測不一樣的是,本以為19秒完成后,第4次會隔2秒在21秒執(zhí)行,沒想到19秒會立即執(zhí)行。

猜測與delay參數(shù)有關(guān),但調(diào)整了delay后仍然一樣,完成的那一秒還是會馬上再執(zhí)行第4次任務(wù)。

通過以上測試對比,我們可以感受到Timer中固定速率和固定延時的區(qū)別,但為了避免出錯,使用Timer時應(yīng)讓TimerTask耗時盡可能短。

4. 其他要點

1.以上是僅第3次任務(wù)加上了耗時11秒,如果是所有任務(wù)都耗時11秒呢?

如果每次任務(wù)執(zhí)行都耗時11秒,那么無論是固定速率還是固定延時,都將是11秒執(zhí)行一個任務(wù)。

2.如果改為schedule(TimerTasktask,DatefirstTime,longperiod)和scheduleAtFixedRate(TimerTasktask,DatefirstTime,longperiod)來調(diào)度任務(wù),firstTime指定為10點,而當前系統(tǒng)時間為11點,會出現(xiàn)什么情況呢?

雖然firstTime已經(jīng)過期,但是Timer將會立即開始執(zhí)行任務(wù),之后按照period間隔重復(fù)執(zhí)行任務(wù)。

3.如果TimerTask執(zhí)行過程中拋出了異常會發(fā)生什么事情?

Timer內(nèi)部僅維護一個線程,當任一TimerTask拋出異常,將導(dǎo)致此線程終止運行,該Timer負責的所有任務(wù)都無法執(zhí)行。

四、調(diào)度多個TimerTask

在上一節(jié)中,介紹的是一個可重復(fù)執(zhí)行的TimeTask,如果執(zhí)行耗時大于設(shè)定的間隔period,將會影響該TimerTask下一次執(zhí)行的時間點。

而這一節(jié)則是為了單獨說明,一個Timer同時調(diào)度多個TimeTask也會互相影響。

示例:

TimerTask task1 = new TimerTask() {
    private int i = 1;
    @Override
    public void run() {
        System.out.print(i + " task1:" + DateUtil.formatNow() + " 開始執(zhí)行, ");
        ThreadUtil.sleep(11 * 1000);
        System.out.println(DateUtil.formatNow() + " 結(jié)束");
        i++;
    }
};
TimerTask task2 = new TimerTask() {
    private int i = 1;
    @Override
    public void run() {
        System.out.print(i + "  task2:" + DateUtil.formatNow() + " 開始執(zhí)行, ");
        ThreadUtil.sleep(11 * 1000);
        System.out.println(DateUtil.formatNow() + " 結(jié)束");
        i++;
    }
};

Timer timer = new Timer("timer");
timer.scheduleAtFixedRate(task1, 5000, 2000);
timer.scheduleAtFixedRate(task2, 5000, 2000);

輸出:

1 task1:2022-10-31 16:58:27 開始執(zhí)行, 2022-10-31 16:58:38 結(jié)束
1 task2:2022-10-31 16:58:38 開始執(zhí)行, 2022-10-31 16:58:49 結(jié)束
2 task2:2022-10-31 16:58:49 開始執(zhí)行, 2022-10-31 16:59:00 結(jié)束
2 task1:2022-10-31 16:59:00 開始執(zhí)行, 2022-10-31 16:59:11 結(jié)束
3 task1:2022-10-31 16:59:11 開始執(zhí)行, 2022-10-31 16:59:22 結(jié)束
3 task2:2022-10-31 16:59:22 開始執(zhí)行, 2022-10-31 16:59:33 結(jié)束
4 task2:2022-10-31 16:59:33 開始執(zhí)行, 2022-10-31 16:59:44 結(jié)束
4 task1:2022-10-31 16:59:44 開始執(zhí)行, 2022-10-31 16:59:55 結(jié)束

可以發(fā)現(xiàn),task1和task2其實都沒有按照既定時間去執(zhí)行任務(wù)了。

根本原因是在于,Timer內(nèi)部僅維護一個線程執(zhí)行所有TimerTask,為了避免錯誤,一個Timer對象最好僅調(diào)度一個TimerTask對象,除非可以確保多個TimerTask之間一定不會相互影響。

因此編寫TimerTask時應(yīng)當自行捕獲異常。

五、取消任務(wù)

Timer在創(chuàng)建時實際上是默認在內(nèi)部維護了一個非守護線程,即使任務(wù)全部執(zhí)行完成,線程也并不會銷毀。

Timer提供cancel()方法,可以手動調(diào)用取消定時器所有的任務(wù),并銷毀定時器。

如果想要Timer內(nèi)部創(chuàng)建的是守護線程,可以使用以下構(gòu)造方法創(chuàng)建定時器,設(shè)置isDaemon為true:

  • Timer(booleanisDaemon)

Timer(Stringname,booleanisDaemon)

如果沒有自己定義name參數(shù),默認Timer內(nèi)部自動命名為“Timer-遞增序號”,作為內(nèi)部線程的線程名稱,在構(gòu)造方法內(nèi)啟動此線程。

如果是要取消單個任務(wù),可以使用TimerTask的cancel()方法。

當TimerTask調(diào)用cancel之后,任務(wù)是取消了,但Timer自身并不能馬上知道TimerTask被取消,而是在準備執(zhí)行前才知道,因此Timer內(nèi)部還維護著這個任務(wù)的引用。若希望Timer立即清除引用,可調(diào)用Timer.purge()立即執(zhí)行清除。

到此這篇關(guān)于Java Timer使用講解的文章就介紹到這了,更多相關(guān)Java Timer使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot如何用java生成靜態(tài)html

    SpringBoot如何用java生成靜態(tài)html

    這篇文章主要介紹了SpringBoot如何用java生成靜態(tài)html,文章圍繞主題展開詳細的內(nèi)容介紹,需要的朋友可以參考一下
    2022-06-06
  • Java動態(tài)代理四種實現(xiàn)方式詳解

    Java動態(tài)代理四種實現(xiàn)方式詳解

    這篇文章主要介紹了Java四種動態(tài)代理實現(xiàn)方式,對于開始學習java動態(tài)代理或者要復(fù)習java動態(tài)代理的朋友來講很有參考價值,有感興趣的朋友可以參考一下
    2021-04-04
  • 在SSM框架中將圖片上傳到數(shù)據(jù)庫中的實現(xiàn)代碼

    在SSM框架中將圖片上傳到數(shù)據(jù)庫中的實現(xiàn)代碼

    這篇文章主要介紹了在SSM框架中將圖片上傳到數(shù)據(jù)庫中的實現(xiàn)代碼,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • java文件讀寫工具類分享

    java文件讀寫工具類分享

    這篇文章主要為大家詳細介紹了java文件讀寫工具類,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • Java8中List轉(zhuǎn)換String字符串幾種方式

    Java8中List轉(zhuǎn)換String字符串幾種方式

    這篇文章主要給大家介紹了關(guān)于Java8中List轉(zhuǎn)換String字符串的幾種方式,在實際開發(fā)中經(jīng)常遇到List轉(zhuǎn)為String字符串的情況,文中給出了幾種方法的示例代碼,需要的朋友可以參考下
    2023-07-07
  • 基于雪花算法實現(xiàn)增強版ID生成器詳解

    基于雪花算法實現(xiàn)增強版ID生成器詳解

    這篇文章主要為大家詳細介紹了如何基于雪花算法實現(xiàn)增強版ID生成器,文中的示例代碼講解詳細,對我們學習具有一定的借鑒價值,需要的可以了解一下
    2022-10-10
  • SpringBoot自定義全局異常處理器的問題總結(jié)

    SpringBoot自定義全局異常處理器的問題總結(jié)

    Springboot框架提供兩個注解幫助我們十分方便實現(xiàn)全局異常處理器以及自定義異常,處理器會優(yōu)先處理更具體的異常類型,如果沒有找到匹配的處理器,那么它會尋找處理更一般異常類型的處理器,本文介紹SpringBoot自定義全局異常處理器的問題,一起看看吧
    2024-01-01
  • java清除u盤內(nèi)存卡里的垃圾文件示例

    java清除u盤內(nèi)存卡里的垃圾文件示例

    手機內(nèi)存卡空間被用光了,但又不知道哪個文件占用了太大,一個個文件夾去找又太麻煩,開發(fā)了個小程序把手機所有文件(包括路徑下所有層次子文件夾下的文件)進行一個排序,這樣你就可以找出哪個文件占用了內(nèi)存太大了
    2014-02-02
  • Java8?lambda表達式的10個實例講解

    Java8?lambda表達式的10個實例講解

    這篇文章主要介紹了Java8?lambda表達式的10個實例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • java模擬http的Get/Post請求,并設(shè)置ip與port代理的方法

    java模擬http的Get/Post請求,并設(shè)置ip與port代理的方法

    下面小編就為大家?guī)硪黄猨ava模擬http的Get/Post請求,并設(shè)置ip與port代理的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-02-02

最新評論