我國基層政府網(wǎng)站建設(shè)情況關(guān)鍵詞seo是什么
IDE:IntelliJ IDEA 2022.2.3 x64
操作系統(tǒng):win10 x64 位 家庭版
JDK: 1.8
文章目錄
- 一、Timer類是什么?
- 二、Timer類主要由哪些部分組成?
- 1.TaskQueue
- 2. TimerThread
- 三、示例代碼分析
- 四、自定義TimerTask為什么會發(fā)生任務(wù)相互阻塞的問題?
- 4.1 使用schedule添加任務(wù),如任務(wù)執(zhí)行超時,會導(dǎo)致任務(wù)丟失(少執(zhí)行)
- 4.2 使用scheduleAtFixedRate添加任務(wù),如任務(wù)執(zhí)行超時,會導(dǎo)致任務(wù)執(zhí)行時間亂掉,下一個任務(wù)會馬上執(zhí)行
- 五、Timer類的應(yīng)用特性
- 六、如何解決任務(wù)阻塞問題?
提示:以下是本篇文章正文內(nèi)容,下面案例可供參考
一、Timer類是什么?
Java Timer類是一個用于調(diào)度任務(wù)的類,它可以在指定的時間間隔內(nèi)執(zhí)行一次或多次任務(wù)。它提供了一種簡單的方式來安排和執(zhí)行定時任務(wù),可以用于各種應(yīng)用程序中,如計劃任務(wù)、定時器等。
Java Timer類位于java.util包中,它有兩個主要的子類:Timer和TimerTask。其中,Timer類用于調(diào)度任務(wù),而TimerTask類則表示一個具體的任務(wù),需要實現(xiàn)run()方法來定義任務(wù)的具體行為。
使用Java Timer類可以方便地創(chuàng)建和管理定時任務(wù),但需要注意的是,它的精度有限,如果需要更高精度的任務(wù)調(diào)度,可以考慮使用ScheduledThreadPoolExecutor等其他工具。
二、Timer類主要由哪些部分組成?
1.TaskQueue
官方解釋
The timer task queue:This data structure is shared with the timer thread. The timer produces tasks, via its various schedule calls, and
the timer thread consumes, executing timer tasks as appropriate, and
removing them from the queue when they’re obsolete.
一句話,就是一個用于存儲和處理任務(wù)的隊列,里面存放TimeTask
2. TimerThread
官方解釋
The timer thread.
顯而易見,就是處理線任務(wù)的線程
三、示例代碼分析
示例代碼如下所示
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;public class myTimerTest {public static void main(String[] args){Timer timer = new Timer(); //任務(wù)執(zhí)行for (int i = 0; i < 2 ; i++) {TimerTask timerTask = new FooTimerTask("FooTimerTask"+i);//將timerTask以當(dāng)前時間執(zhí)行,以2秒時間為間隔再次觸發(fā),即12:00:00執(zhí)行,那么12:00:02 會再次觸發(fā)執(zhí)行timer.schedule(timerTask,new Date(),2000);//任務(wù)添加}}
}class FooTimerTask extends TimerTask {private String name;public FooTimerTask(String name) {this.name = name;}@Overridepublic void run() {try {System.out.println(name+" - startTime = "+new Date());//延遲3秒執(zhí)行Thread.sleep(3000);System.out.println(name+" - endTime = "+new Date());} catch (InterruptedException e) {e.printStackTrace();}}
}
注意
其中,任務(wù)會在 Timer timer = new Timer();時執(zhí)行,而并非大家認(rèn)為的在timer.schedule(timerTask,new Date(),2000);時執(zhí)行,該代碼是將該timerTask添加到TaskQueue中(任務(wù)隊列中)
不信,請看如下的源代碼
①在new Timer()時執(zhí)行任務(wù)
②在timer.schedule(timerTask,new Date(),2000)時添加任務(wù)至任務(wù)隊列中
通過上述源代碼演示,Timer類是在new Timer()中以多線程的方式運(yùn)行TimerThread的start()方法,進(jìn)而調(diào)用其中的run()方法。而我們自子自定義的FooTimerTask 的run()方法卻是以單線程的方式被調(diào)用。
在TimerThread中的run方法中mainLoop方法里以死循環(huán)不斷檢查是否有任務(wù)需要開始執(zhí)行了,有就執(zhí)行它,執(zhí)行任務(wù)也是用這個線程執(zhí)行。
何以見得?
在mainLoop方法中
我們自定義的FooTimerTask會以單線程的方式執(zhí)行,這樣任務(wù)可能會相互阻塞
四、自定義TimerTask為什么會發(fā)生任務(wù)相互阻塞的問題?
4.1 使用schedule添加任務(wù),如任務(wù)執(zhí)行超時,會導(dǎo)致任務(wù)丟失(少執(zhí)行)
示例代碼如下所示
public class myTimerTest {public static void main(String[] args){Timer timer = new Timer(); //任務(wù)執(zhí)行for (int i = 0; i < 2 ; i++) {TimerTask timerTask = new FooTimerTask("FooTimerTask"+i);//將timerTas以當(dāng)前時間執(zhí)行,間隔2s后觸發(fā)執(zhí)行,比如在12:00:00執(zhí)行timerTas,下一次觸發(fā)就是12:00:02時執(zhí)行,余者類推timer.schedule(timerTask,new Date(),2000);//任務(wù)添加}}
}class FooTimerTask extends TimerTask {private String name;public FooTimerTask(String name) {this.name = name;}@Overridepublic void run() {try {System.out.println(name+" - startTime = "+new Date());//延遲3秒執(zhí)行Thread.sleep(3000);System.out.println(name+" - endTime = "+new Date());} catch (InterruptedException e) {e.printStackTrace();}}
}
示例運(yùn)行如下
這里有個問題:根據(jù)上述代碼定義,自定義timerTask會在間隔2s后執(zhí)行,而timerTask自己的執(zhí)行會延遲3s才會真正結(jié)束,那么我們所推測它的執(zhí)行場景應(yīng)該是這樣的:
假如任務(wù)A在12:00:00開始執(zhí)行,12:00:03執(zhí)行結(jié)束,那么下一個任務(wù)B將會在12:00:05開始執(zhí)行
但上述代碼的運(yùn)行結(jié)果卻與我們的推測 大相徑庭
思考①
那如果timerTask去掉延遲3s的代碼,運(yùn)行結(jié)果應(yīng)該是如“任務(wù)A在12:00:00開始執(zhí)行,12:00:0執(zhí)行結(jié)束,那么下一個任務(wù)B將會在12:00:03開始執(zhí)行”這樣執(zhí)行吧?
代碼示例如下
class FooTimerTask extends TimerTask {private String name;public FooTimerTask(String name) {this.name = name;}@Overridepublic void run() {System.out.println(name+" - startTime = "+new Date());System.out.println(name+" - endTime = "+new Date());
// try {
// System.out.println(name+" - startTime = "+new Date());
// //延遲3秒執(zhí)行
// Thread.sleep(3000);
// System.out.println(name+" - endTime = "+new Date());
// } catch (InterruptedException e) {
// e.printStackTrace();
// }}
}
運(yùn)行如下
看來,任務(wù)阻塞的問題就出現(xiàn)在延遲3s的代碼上
思考②
如果一個任務(wù)本身執(zhí)行時間過長,超過預(yù)設(shè)的時間間隔(即任務(wù)執(zhí)行超時),為什么會發(fā)生任務(wù)阻塞的問題?
任務(wù)阻塞問題;會導(dǎo)致后面的任務(wù)往后推移,預(yù)想在這個間隔內(nèi)存在的任務(wù)執(zhí)行就沒了,任務(wù)少執(zhí)行了【假如在10s的時間段內(nèi),任務(wù)正常執(zhí)行5次,假如發(fā)生任務(wù)超時,可能會執(zhí)行3-4次】
通過如下追蹤源代碼可知
①追蹤進(jìn)入schedule()方法中
注意:schedule方法將period值加了負(fù)號,即-period
②追蹤進(jìn)入sched()方法中
任務(wù)task的nextExecutionTime被賦值為time(傳入的時間)
③追蹤進(jìn)入run()方法中的mainLoop()方法中
④追蹤進(jìn)入queue.rescheduleMin()方法中
⑤追蹤進(jìn)入fixDown()方法中
結(jié)論
由此可知,schedule里Timertask真正的執(zhí)行時間取決上一個任務(wù)的結(jié)束時間,并非以預(yù)設(shè)的時間為準(zhǔn),故如某一個任務(wù)執(zhí)行超時,則有可能出現(xiàn)任務(wù)丟失的問題
4.2 使用scheduleAtFixedRate添加任務(wù),如任務(wù)執(zhí)行超時,會導(dǎo)致任務(wù)執(zhí)行時間亂掉,下一個任務(wù)會馬上執(zhí)行
示例代碼如下所示
public class myTimerTest {public static void main(String[] args){Timer timer = new Timer(); //任務(wù)執(zhí)行for (int i = 0; i < 2 ; i++) {TimerTask timerTask = new FooTimerTask("FooTimerTask"+i);timer.scheduleAtFixedRate(timerTask,new Date(),2000);}}
}class FooTimerTask extends TimerTask {private String name;public FooTimerTask(String name) {this.name = name;}@Overridepublic void run() {try {System.out.println(name+" - startTime = "+new Date());//延遲3秒執(zhí)行Thread.sleep(3000);System.out.println(name+" - endTime = "+new Date());} catch (InterruptedException e) {e.printStackTrace();}}
}
運(yùn)行如下
思考
為什么一旦任務(wù)發(fā)生超時,下一個任務(wù)會馬上觸發(fā)執(zhí)行?
通過如下追蹤源代碼可知
①追蹤進(jìn)入schedule()方法中
②追蹤進(jìn)入sched()方法中
任務(wù)task的nextExecutionTime被賦值為time(傳入的時間)
③追蹤進(jìn)入run()方法中的mainLoop()方法中
注:剩余追蹤步驟和4.1小節(jié)一致,故不予展示
結(jié)論
scheduLeAtFixedRate()方法會嚴(yán)格按照預(yù)設(shè)時間作為TimerTask的執(zhí)行時間,如果發(fā)生任務(wù)超時,下一個任務(wù)會直接觸發(fā)
五、Timer類的應(yīng)用特性
- 運(yùn)行時異常會導(dǎo)致timer線程終止
- 任務(wù)調(diào)度是基于絕對時間的,對系統(tǒng)時間敏感
六、如何解決任務(wù)阻塞問題?
解決方案
在自定義TimerTask里的run()方法里使用線程池去執(zhí)行,即可解決上述問題