Java应用程序中定时执行任务Word格式.docx
- 文档编号:7928511
- 上传时间:2023-05-09
- 格式:DOCX
- 页数:26
- 大小:66.66KB
Java应用程序中定时执行任务Word格式.docx
《Java应用程序中定时执行任务Word格式.docx》由会员分享,可在线阅读,更多相关《Java应用程序中定时执行任务Word格式.docx(26页珍藏版)》请在冰点文库上搜索。
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,在指定的分钟数之后执行。
时间到了,Timer就在后台调用TimerTask的start()方法,这会使它发出声音。
在取消计时器后这个应用程序就会中止。
计划重复执行的任务
通过指定一个固定的执行频率或者固定的执行时间间隔,Timer可以对重复执行的任务进行计划。
不过,有许多应用程序要求更复杂的计划。
例如,每天清晨在同一时间发出叫醒铃声的闹钟不能简单地使用固定的计划频率86400000毫秒(24小时),因为在钟拨快或者拨慢(如果您的时区使用夏令时)的那些天里,叫醒可能过晚或者过早。
解决方案是使用日历算法计算每日事件下一次计划发生的时间。
而这正是计划框架所支持的。
考虑清单2中的AlarmClock实现:
清单2.AlarmClock类
importjava.text.SimpleDateFormat;
importjava.util.Date;
importorg.tiling.scheduling.Scheduler;
importorg.tiling.scheduling.SchedulerTask;
importorg.tiling.scheduling.examples.iterators.DailyIterator;
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;
scheduler.schedule(newSchedulerTask(){
soundAlarm();
privatevoidsoundAlarm(){
Wakeup!
"
+
It&
quots"
+dateFormat.format(newDate()));
//Startanewthreadtosoundanalarm...
},newDailyIterator(hourOfDay,minute,second));
AlarmClockalarmClock=newAlarmClock(7,0,0);
alarmClock.start();
注意这段代码与煮蛋计时器应用程序非常相似。
AlarmClock实例拥有一个Scheduler(而不是Timer)实例,用于提供必要的计划。
启动后,这个闹钟对SchedulerTask(而不是TimerTask)进行调度用以发出报警声。
这个闹钟不是计划一个任务在固定的延迟时间后执行,而是用DailyIterator类描述其计划。
在这里,它只是计划任务在每天上午7:
00执行。
下面是一个正常运行情况下的输出:
It&
quots24Aug200307:
00:
00.023
quots25Aug200307:
00.001
quots26Aug200307:
00.058
quots27Aug200307:
00.015
quots28Aug200307:
00.002
...
DailyIterator实现了ScheduleIterator,这是一个将SchedulerTask的计划执行时间指定为一系列java.util.Date对象的接口。
然后next()方法按时间先后顺序迭代Date对象。
返回值null会使任务取消(即它再也不会运行)——这样的话,试图再次计划将会抛出一个异常。
清单3包含ScheduleIterator接口:
清单3.ScheduleIterator接口
packageorg.tiling.scheduling;
publicinterfaceScheduleIterator{
publicDatenext();
DailyIterator的next()方法返回表示每天同一时间(上午7:
00)的Date对象,如清单4所示。
所以,如果对新构建的next()类调用next(),那么将会得到传递给构造函数的那个日期当天或者后面一天的7:
00AM。
再次调用next()会返回后一天的7:
00AM,如此重复。
为了实现这种行为,DailyIterator使用了java.util.Calendar实例。
构造函数会在日历中加上一天,对日历的这种设置使得第一次调用next()会返回正确的Date。
注意代码没有明确地提到夏令时修正,因为Calendar实现(在本例中是GregorianCalendar)负责对此进行处理,所以不需要这样做。
清单4.DailyIterator类
packageorg.tiling.scheduling.examples.iterators;
importorg.tiling.scheduling.ScheduleIterator;
importjava.util.Calendar;
/**
*ADailyIteratorclassreturnsasequenceofdatesonsubsequentdays
*representingthesametimeeachday.
*/
publicclassDailyIteratorimplementsScheduleIterator{
privatefinalCalendarcalendar=Calendar.getInstance();
publicDailyIterator(inthourOfDay,intminute,intsecond){
this(hourOfDay,minute,second,newDate());
publicDailyIterator(inthourOfDay,intminute,intsecond,Datedate){
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY,hourOfDay);
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();
实现计划框架
在上一节,我们学习了如何使用计划框架,并将它与Java定时器框架进行了比较。
下面,我将向您展示如何实现这个框架。
除了清单3中展示的ScheduleIterator接口,构成这个框架的还有另外两个类——Scheduler和SchedulerTask。
这些类实际上在内部使用Timer和SchedulerTask,因为计划其实就是一系列的单次定时器。
清单5和6显示了这两个类的源代码:
清单5.Scheduler
publicclassScheduler{
classSchedulerTimerTaskextendsTimerTask{
privateSchedulerTaskschedulerTask;
privateScheduleIteratoriterator;
publicSchedulerTimerTask(SchedulerTaskschedulerTask,
ScheduleIteratoriterator){
this.schedulerTask=schedulerTask;
this.iterator=iterator;
schedulerTask.run();
reschedule(schedulerTask,iterator);
publicScheduler(){
publicvoidcancel(){
publicvoidschedule(SchedulerTaskschedulerTask,
Datetime=iterator.next();
if(time==null){
schedulerTask.cancel();
}else{
synchronized(schedulerTask.lock){
if(schedulerTask.state!
=SchedulerTask.VIRGIN){
thrownewIllegalStateException("
Taskalready
scheduled"
+"
orcancelled"
schedulerTask.state=SchedulerTask.SCHEDULED;
schedulerTask.timerTask=
newSchedulerTimerTask(schedulerTask,iterator);
timer.schedule(schedulerTask.timerTask,time);
privatevoidreschedule(SchedulerTaskschedulerTask,
=SchedulerTask.CANCELLED){
清单6显示了SchedulerTask类的源代码:
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(){
returntimerTask==null?
0:
timerTask.scheduledExecutionTime();
就像煮蛋计时器,Scheduler的每一个实例都拥有Timer的一个实例,用于提供底层计划。
Scheduler并没有像实现煮蛋计时器时那样使用一个单次定时器,它将一组单次定时器串接在一起,以便在由ScheduleIterator指定的各个时间执行SchedulerTask类。
考虑Scheduler上的publicschedule()方法——这是计划的入口点,因为它是客户调用的方法(在取消任务一节中将描述仅有的另一个public方法cancel())。
通过调用ScheduleIterator接口的next(),发现第一次执行SchedulerTask的时间。
然后通过调用底层Timer类的单次schedule()方法,启动计划在这一时刻执行。
为单次执行提供的TimerTask对象是嵌入的SchedulerTimerTask类的一个实例,它包装了任务和迭代器(iterator)。
在指定的时间,调用嵌入类的run()方法,它使用包装的任务和迭代器引用以便重新计划任务的下一次执行。
reschedule()方法与schedule()方法非常相似,只不过它是private的,并且执行一组稍有不同的SchedulerTask状态检查。
重新计划过程反复重复,为每次计划执行构造一个新的嵌入类实例,直到任务或者调度程序被取消(或者JVM关闭)。
类似于TimerTask,SchedulerTask在其生命周期中要经历一系列的状态。
创建后,它处于VIRGIN状态,这表明它从没有计划过。
计划以后,它就变为SCHEDULED状态,再用下面描述的方法之一取消任务后,它就变为CANCELLED状态。
管理正确的状态转变——如保证不对一个非VIRGIN状态的任务进行两次计划——增加了Scheduler和SchedulerTask类的复杂性。
在进行可能改变任务状态的操作时,代码必须同步任务的锁对象。
取消任务
取消计划任务有三种方式。
第一种是调用SchedulerTask的cancel()方法。
这很像调用TimerTask的cancel()方法:
任务再也不会运行了,不过已经运行的任务仍会运行完成。
cancel()方法的返回值是一个布尔值,表示如果没有调用cancel()的话,计划的任务是否还会运行。
更准确地说,如果任务在调用cancel()之前是SCHEDULED状态,那么它就返回true。
如果试图再次计划一个取消的(甚至是已计划的)任务,那么Scheduler就会抛出一个IllegalStateException。
取消计划任务的第二种方式是让ScheduleIterator返回null。
这只是第一种方式的简化操作,因为Scheduler类调用SchedulerTask类的cancel()方法。
如果您想用迭代器而不是任务来控制计划停止时间时,就用得上这种取消任务的方式了。
第三种方式是通过调用其cancel()方法取消整个Scheduler。
这会取消调试程序的所有任务,并使它不能再计划任何任务。
扩展cron实用程序
可以将计划框架比作UNIX的cron实用程序,只不过计划次数的规定是强制性而不是声明性的。
例如,在AlarmClock实现中使用的DailyIterator类,它的计划与cron作业的计划相同,都是由以07***开始的crontab项指定的(这些字段分别指定分钟、小时、日、月和星期)。
不过,计划框架比cron更灵活。
想像一个在早晨打开热水的HeatingController应用程序。
我想指示它“在每个工作日上午8:
00打开热水,在周未上午9:
00打开热水”。
使用cron,我需要两个crontab项(08**1,2,3,4,5和09**6,7)。
而使用ScheduleIterator的解决方案更简洁一些,因为我可以使用复合(composition)来定义单一迭代器。
清单7显示了其中的一种方法:
清单7.用复合定义单一迭代器
int[]weekdays=newint[]{
Calendar.MONDAY,
Calendar.TUESDAY,
Calendar.WEDNESDAY,
Calendar.THURSDAY,
Calendar.FRIDAY
};
int[]weekend=newint[]{
Calendar.SATURDAY,
Calendar.SUNDAY
ScheduleIteratori=newCompositeIterator(
newScheduleIterator[]{
newRestrictedDailyIterator(8,0,0,weekdays),
newRestrictedDailyIterator(9,0,0,weekend)
);
RestrictedDailyIterator类很像DailyIterator,只不过它限制为只在一周的特定日子里运行,而一个Co
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Java 应用程序 定时 执行 任务