版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
所有類型的Java應(yīng)用程序一般都需要計劃重復(fù)執(zhí)行的任務(wù)。企業(yè)應(yīng)用程序需要計劃每日的日志或者晚間批處理過程。一個J2SE或者J2ME日歷應(yīng)用程序需要根據(jù)用戶的約定計劃鬧鈴時間。不過,標(biāo)準(zhǔn)的調(diào)度類Timer和TimerTask沒有足夠的靈活性,無法支持通常需要的計劃任務(wù)類型。在本文中,Java開發(fā)人員TomWhite向您展示了如何構(gòu)建一個簡單通用的計劃框架,以用于執(zhí)行任意復(fù)雜的計劃任務(wù)。我將把java.util.Timer和java.util.TimerTask統(tǒng)稱為Java計時器框架,它們使程序員可以很容易地計劃簡單的任務(wù)(注意這些類也可用于J2ME中)。在Java2SDK,StandardEdition,Version1.3中引入這個框架之前,開發(fā)人員必須編寫自己的調(diào)度程序,這需要花費很大精力來處理線程和復(fù)雜的Object.wait()方法。不過,Java計時器框架沒有足夠的能力來滿足許多應(yīng)用程序的計劃要求。甚至一項需要在每天同一時間重復(fù)執(zhí)行的任務(wù),也不能直接使用Timer來計劃,因為在夏令時開始和結(jié)束時會出現(xiàn)時間跳躍。本文展示了一個通用的Timer和TimerTask計劃框架,從而允許更靈活的計劃任務(wù)。這個框架非常簡單一一它包括兩個類和一個接口一一并且容易掌握。如果您習(xí)慣于使用Java定時器框架,那么您應(yīng)該可以很快地掌握這個計劃框架。計劃單次任務(wù)計劃框架建立在Java定時器框架類的基礎(chǔ)之上。因此,在解釋如何使用計劃框架以及如何實現(xiàn)它之前,我們將首先看看如何用這些類進行計劃。想像一個煮蛋計時器,在數(shù)分鐘之后(這時蛋煮好了)它會發(fā)出聲音提醒您。清單1中的代碼構(gòu)成了一個簡單的煮蛋計時器的基本結(jié)構(gòu),它用Java語言編寫:清單1.EggTimer類packageorg.tiling.scheduling.examples;importjava.util.Timer;importjava.util.TimerTask;publicclassEggTimer(privatefinalTimertimer=newTimer();privatefinalintminutes;publicEggTimer(intminutes)(this.minutes=minutes;}publicvoidstart()(timer.schedule(newTimerTask()(publicvoidrun()(playSound();timer.cancel();}privatevoidplaySound()(System.out.println("Youreggisready!");//Startanewthreadtoplayasound...}},minutes*60*1000);}publicstaticvoidmain(String[]args)(EggTimereggTimer=newEggTimer(2);eggTimer.start();}}EggTimer實例擁有一個Timer實例,用于提供必要的計劃。用start()方法啟動煮蛋計時器后,它就計劃了一個TimerTask,在指定的分鐘數(shù)之后執(zhí)行。時間到了,Timer就在后臺調(diào)用TimerTask的start()方法,這會使它發(fā)出聲音。在取消計時器后這個應(yīng)用程序就會中止。計劃重復(fù)執(zhí)行的任務(wù)通過指定一個固定的執(zhí)行頻率或者固定的執(zhí)行時間間隔,Timer可以對重復(fù)執(zhí)行的任務(wù)進行計劃。不過,有許多應(yīng)用程序要求更復(fù)雜的計劃。例如,每天清晨在同一時間發(fā)出叫醒鈴聲的鬧鐘不能簡單地使用固定的計劃頻率86400000毫秒(24小時),因為在鐘撥快或者撥慢(如果您的時區(qū)使用夏令時)的那些天里,叫醒可能過晚或者過早。解決方案是使用日歷算法計算每日事件下一次計劃發(fā)生的時間。而這正是計劃框架所支持的。考慮清單2中的AlarmClock實現(xiàn):清單2.AlarmClock類packageorg.tiling.scheduling.examples;importjava.text.SimpleDateFormat;importjava.util.Date;importorg.tiling.scheduling.Scheduler;importorg.tiling.scheduling.SchedulerTask;importorg.tiling.scheduling.examples.iterators.Dailylterator;publicclassAlarmClock(privatefinalSchedulerscheduler=newScheduler();privatefinalSimpleDateFormatdateFormat=newSimpleDateFormat("ddMMMyyyyHH:mm:ss.SSS");privatefinalinthourOfDay,minute,second;publicAlarmClock(inthourOfDay,intminute,intsecond)(this.hourOfDay=hourOfDay;this.minute=minute;this.second=second;}publicvoidstart()(scheduler.schedule(newSchedulerTask()(publicvoidrun()(soundAlarm();}privatevoidsoundAlarm()(System.out.println("Wakeup!"+"It's"+dateFormat.format(newDate()));//Startanewthreadtosoundanalarm...}},newDailyIterator(hourOfDay,minute,second));}publicstaticvoidmain(String[]args)(AlarmClockalarmClock=newAlarmClock(7,0,0);alarmClock.start();}}注意這段代碼與煮蛋計時器應(yīng)用程序非常相似。AlarmClock實例擁有一個Scheduler(而不是Timer)實例,用于提供必要的計劃。啟動后,這個鬧鐘對SchedulerTask(而不是TimerTask)進行調(diào)度用以發(fā)出報警聲。這個鬧鐘不是計劃一個任務(wù)在固定的延遲時間后執(zhí)行,而是用DailyIterator類描述其計劃。在這里,它只是計劃任務(wù)在每天上午7:00執(zhí)行。下面是一個正常運行情況下的輸出:Wakeup!It's24Aug200307:00:00.023Wakeup!It's25Aug200307:00:00.001Wakeup!It's26Aug200307:00:00.058Wakeup!It's27Aug200307:00:00.015Wakeup!It's28Aug200307:00:00.002DailyIterator實現(xiàn)了ScheduleIterator,這是一個將SchedulerTask的計劃執(zhí)行時間指定為一系列java.util.Date對象的接口。然后next()方法按時間先后順序迭代Date對象。返回值null會使任務(wù)取消(即它再也不會運行)一一這樣的話,試圖再次計劃將會拋出一個異常。清單3包含ScheduleIterator接口:清單3.Schedulelterator接口packageorg.tiling.scheduling;importjava.util.Date;publicinterfaceScheduleIterator(publicDatenext();}DailyIterator的next()方法返回表示每天同一時間(上午7:00)的Date對象,如清單4所示。所以,如果對新構(gòu)建的next()類調(diào)用next(),那么將會得到傳遞給構(gòu)造函數(shù)的那個日期當(dāng)天或者后面一天的7:00AM。再次調(diào)用next()會返回后一天的7:00AM,如此重復(fù)。為了實現(xiàn)這種行為,DailyIterator使用了java.util.Calendar實例。構(gòu)造函數(shù)會在日歷中加上一天,對日歷的這種設(shè)置使得第一次調(diào)用next()會返回正確的Date。注意代碼沒有明確地提到夏令時修正,因為Calendar實現(xiàn)(在本例中是GregorianCalendar)負責(zé)對此進行處理,所以不需要這樣做。清單4.DailyIterator類packageorg.tiling.scheduling.examples.iterators;importorg.tiling.scheduling.ScheduleIterator;importjava.util.Calendar;importjava.util.Date;/**ADailyIteratorclassreturnsasequenceofdatesonsubsequentdaysrepresentingthesametimeeachday.*/publicclassDailyIteratorimplementsScheduleIterator(privatefinalinthourOfDay,minute,second;privatefinalCalendarcalendar=Calendar.getInstance();publicDailyIterator(inthourOfDay,intminute,intsecond)(this(hourOfDay,minute,second,newDate());}publicDailyIterator(inthourOfDay,intminute,intsecond,Datedate)(this.hourOfDay=hourOfDay;this.minute=minute;this.second=second;calendar.setTime(date);calendar.set(Calendar.HOUR_OF_DAYhourOfDay);calendar.set(Calendar.MINUTE,minute);calendar.set(Calendar.SECOND,second);calendar.set(Calendar.MILLISECOND,0);if(!calendar.getTime().before(date))(calendar.add(Calendar.DATE,-1);}}publicDatenext()(calendar.add(Calendar.DATE,1);returncalendar.getTime();}}文章轉(zhuǎn)載自網(wǎng)管網(wǎng):/plus/view.php2aidH23605實現(xiàn)計劃框架在上一節(jié),我們學(xué)習(xí)了如何使用計劃框架,并將它與Java定時器框架進行了比較。下面,我將向您展示如何實現(xiàn)這個框架。除了清單3中展示的Scheduleiterator接口,構(gòu)成這個框架的還有另外兩個類Scheduler和SchedulerTask。這些類實際上在內(nèi)部使用Timer和SchedulerTask,因為計劃其實就是一系列的單次定時器。清單5和6顯示了這兩個類的源代碼:清單5.Schedulerpackageorg.tiling.scheduling;importjava.util.Date;importjava.util.Timer;importjava.util.TimerTask;publicclassScheduler(classSchedulerTimerTaskextendsTimerTask(privateSchedulerTaskschedulerTask;privateScheduleiteratoriterator;publicSchedulerTimerTask(SchedulerTaskschedulerTask,Scheduleiteratoriterator)(this.schedulerTask=schedulerTask;this.iterator=iterator;}publicvoidrun()(schedulerTask.run();reschedule(schedulerTask,iterator);}}privatefinalTimertimer=newTimer();publicScheduler()(}publicvoidcancel()(timer.cancel();}publicvoidschedule(SchedulerTaskschedulerTask,ScheduleIteratoriterator)(Datetime=iterator.next();if(time==null)(schedulerTask.cancel();}else(synchronized(schedulerTask.lock)(if(schedulerTask.state!=SchedulerTask.VIRGIN)(thrownewIllegalStateException("Taskalreadyscheduled"+"orcancelled");}schedulerTask.state=SchedulerTask.SCHEDULED;schedulerTask.timerTask=newSchedulerTimerTask(schedulerTask,iterator);timer.schedule(schedulerTask.timerTask,time);}}}privatevoidreschedule(SchedulerTaskschedulerTask,ScheduleIteratoriterator)(Datetime=iterator.next();if(time==null)(schedulerTask.cancel();}else(synchronized(schedulerTask.lock)(if(schedulerTask.state!=SchedulerTask.CANCELLED)(schedulerTask.timerTask=newSchedulerTimerTask(schedulerTask,iterator);timer.schedule(schedulerTask.timerTask,time);}}}}}清單6顯示了SchedulerTask類的源代碼:packageorg.tiling.scheduling;importjava.util.TimerTask;publicabstractclassSchedulerTaskimplementsRunnable(finalObjectlock=newObject();intstate=VIRGIN;staticfinalintVIRGIN=0;staticfinalintSCHEDULED=1;staticfinalintCANCELLED=2;TimerTasktimerTask;protectedSchedulerTask()(}publicabstractvoidrun();publicbooleancancel()(synchronized(lock)(if(timerTask!=null)(timerTask.cancel();}booleanresult=(state==SCHEDULED);state=CANCELLED;returnresult;publiclongscheduledExecutionTime()(synchronized(lock)(returntimerTask==null?0:timerTask.scheduledExecutionTime();}}}就像煮蛋計時器,Scheduler的每一個實例都擁有Timer的一個實例,用于提供底層計劃。Scheduler并沒有像實現(xiàn)煮蛋計時器時那樣使用一個單次定時器,它將一組單次定時器串接在一起,以便在由Scheduleiterator指定的各個時間執(zhí)行SchedulerTask類??紤]Scheduler上的publicschedule()方法這是計劃的入口點,因為它是客戶調(diào)用的方法(在取消任務(wù)一節(jié)中將描述僅有的另一個public方法cancel。)。通過調(diào)用Scheduleiterator接口的next(),發(fā)現(xiàn)第一次執(zhí)行SchedulerTask的時間。然后通過調(diào)用底層Timer類的單次schedule()方法,啟動計劃在這一時刻執(zhí)行。為單次執(zhí)行提供的TimerTask對象是嵌入的SchedulerTimerTask類的一個實例,它包裝了任務(wù)和迭代器(iterator)。在指定的時間,調(diào)用嵌入類的run()方法,它使用包裝的任務(wù)和迭代器引用以便重新計劃任務(wù)的下一次執(zhí)行。reschedule。方法與schedule()方法非常相似,只不過它是private的,并且執(zhí)行一組稍有不同的SchedulerTask狀態(tài)檢查。重新計劃過程反復(fù)重復(fù),為每次計劃執(zhí)行構(gòu)造一個新的嵌入類實例,直到任務(wù)或者調(diào)度程序被取消(或者JVM關(guān)閉)。類似于TimerTask,SchedulerTask在其生命周期中要經(jīng)歷一系列的狀態(tài)。創(chuàng)建后,它處于VIRGIN狀態(tài),這表明它從沒有計劃過。計劃以后,它就變?yōu)镾CHEDULED狀態(tài),再用下面描述的方法之一取消任務(wù)后,它就變?yōu)镃ANCELLED狀態(tài)。管理正確的狀態(tài)轉(zhuǎn)變——如保證不對一個非VIRGIN狀態(tài)的任務(wù)進行兩次計劃——增加了Scheduler和SchedulerTask類的復(fù)雜性。在進行可能改變?nèi)蝿?wù)狀態(tài)的操作時,代碼必須同步任務(wù)的鎖對象。取消任務(wù)取消計劃任務(wù)有三種方式。第一種是調(diào)用SchedulerTask的cancel()方法。這很像調(diào)用TimerTask的cancel()方法:任務(wù)再也不會運行了,不過已經(jīng)運行的任務(wù)仍會運行完成。cancel()方法的返回值是一個布爾值,表示如果沒有調(diào)用cancel()的話,計劃的任務(wù)是否還會運行。更準(zhǔn)確地說,如果任務(wù)在調(diào)用cancel()之前是SCHEDULED狀態(tài),那么它就返回true。如果試圖再次計劃一個取消的(甚至是已計劃的)任務(wù),那么Scheduler就會拋出一個IllegalStateException。取消計劃任務(wù)的第二種方式是讓ScheduleIterator返回null。這只是第一種方式的簡化操作,因為Scheduler類調(diào)用SchedulerTask類的cancel()方法。如果您想用迭代器而不是任務(wù)來控制計劃停止時間時,就用得上這種取消任務(wù)的方式了。第三種方式是通過調(diào)用其cancel()方法取消整個Scheduler。這會取消調(diào)試程序的所有任務(wù),并使它不能再計劃任何任務(wù)。擴展cron實用程序可以將計劃框架比作UNIX的cron實用程序,只不過計劃次數(shù)的規(guī)定是強制性而不是聲明性的。例如,在AlarmClock實現(xiàn)中使用的Dailyiterato
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2026福建南平市建陽區(qū)文化體育和旅游局招聘1人備考考試題庫附答案解析
- 物業(yè)公司生產(chǎn)責(zé)任制度
- 原材料生產(chǎn)過程管理制度
- 2026重慶市萬州區(qū)燕山鄉(xiāng)人民政府招聘全日制公益性崗位1人備考考試試題附答案解析
- 倉鼠生產(chǎn)管理員工制度
- 生產(chǎn)企業(yè)黑名單制度
- 2026年河北承德市教育局公開選聘急需緊缺學(xué)科教師39名參考考試題庫附答案解析
- 戒毒所生產(chǎn)車間制度
- 周五安全生產(chǎn)會議制度
- 會計員安全生產(chǎn)制度
- 中國醫(yī)護服裝行業(yè)未來發(fā)展趨勢分析及投資規(guī)劃建議研究報告
- 《廣州天河商圈》課件
- H31341 V2.5 HCIP-TranSmission 傳輸網(wǎng)練習(xí)試題及答案
- 下肢靜脈曲張課件
- (高清版)DZT 0428-2023 固體礦產(chǎn)勘查設(shè)計規(guī)范
- XXX縣村鎮(zhèn)空氣源熱泵區(qū)域集中供熱項目可行性研究報告
- 湖州昆侖億恩科電池材料有限公司年產(chǎn)40000噸鋰離子電池電解液項目環(huán)境影響報告
- 幼兒園班級體弱兒管理總結(jié)
- 肥胖患者圍術(shù)期麻醉管理
- 核酸印跡與分子雜交
- 金屬罐三片罐結(jié)構(gòu)分析
評論
0/150
提交評論