任务调度.docx
《任务调度.docx》由会员分享,可在线阅读,更多相关《任务调度.docx(19页珍藏版)》请在冰豆网上搜索。
任务调度
任务调度
从网上发现了好多任务调度的框架,对于小白的编辑来说也很困惑啊,那让我们一起慢慢走近任务调度框架吧!
什么是任务调度
任务调度是操作系统的重要组成部分,而对于实时操作系统,任务调度直接影响其实时性能。
任务调度方式常规可分为:
可打断调度(实时系统基本功能):
关键防止优先级倒置;
不可打断调度:
先来先服务,不可中断。
任务调度算法可分为:
事件驱动调度算法:
根据事件的先后以及任务的优先级安排任务的执行;
时钟驱动调度算法:
一般用于周期任务。
事件驱动调度,依赖外部硬件设备,通过产生中断方式为任务调度提供信号。
分两种:
集成事件驱动调度:
中断的优先级与任务的优先级相对应,中断只有在其优先级高于正在执行的任务时才会被处理器响应。
非集成事件驱动调度:
任务通过外部中断启动,中断优先级与相关任务优先级没有关系。
前言
任务调度是指基于给定时间点,给定时间间隔或者给定执行次数自动执行任务。
本文由浅入深介绍四种任务调度的Java实现:
∙Timer
∙ScheduledExecutor
∙开源工具包Quartz
∙开源工具包JCronTab
Timer
Timer:
是生产者--消费者模型的一种特例:
多生产者,单消费者模型。
优点:
简单易用
缺点:
所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务。
Java代码测试timer:
Timer测试用例一:
packagecom.zx.scheduler;
importjava.util.Timer;
importjava.util.TimerTask;
publicclassTimerTestextendsTimerTask{
privateStringjobName="";
publicTimerTest(StringjobName){
super();
this.jobName=jobName;
}
@Override
publicvoidrun(){
System.out.println("execute"+jobName);
}
publicstaticvoidmain(String[]args){
Timertimer=newTimer();
longdelay1=1*1000;
longperiod1=1000;
//从现在开始1秒钟之后,每隔1秒钟执行一次job1
timer.schedule(newTimerTest("job1"),delay1,period1);
longdelay2=2*1000;
longperiod2=2000;
//从现在开始2秒钟之后,每隔2秒钟执行一次job2
timer.schedule(newTimerTest("job2"),delay2,period2);
}
}
/**
输出结果:
executejob1
executejob1
executejob2
executejob1
……
*/
Timer测试用例二:
packagecom.zx.scheduler;
importjava.util.Date;
importjava.util.Timer;
importjava.util.TimerTask;
publicclassPlainTimerTaskextendsTimerTask{
@Override
publicvoidrun(){
System.out.println("输出时间:
"+newDate());
}
publicstaticvoidmain(String[]args){
Timertimer=newTimer();
timer.schedule(newPlainTimerTask(),5000L);
}
}
/**
*输出时间:
MonFeb2911:
16:
49CST2016
*/
Timer测试用例三:
packagecom.zx.test;
importjava.util.Timer;
importjava.util.TimerTask;
publicclassTimerTestextendsTimerTask{
staticintflax=0;
@Override
publicvoidrun(){
System.out.println("test"+flax);
flax++;
}
publicstaticvoidmain(String[]args){
Timert=newTimer();
longdelay=1000;
longperiod=10*1000;
t.schedule(newTimerTest(),delay,period);//从现在开始1秒钟之后,每隔10秒钟执行一次
}
}
/**结果
test0
test1
test2
test3
*/
ScheduledExecutor
ScheduledExecutor:
其设计思想是,每一个被调度的任务都会由线程池中一个线程去执行,因此任务是并发执行的,相互之间不会受到干扰。
需要注意的是,只有当任务的执行时间到来时,ScheduedExecutor才会真正启动一个线程,其余时间ScheduledExecutor都是在轮询任务的状态。
Java代码测试ScheduledExecutor
packagecom.zx.scheduler;
importjava.util.concurrent.Executors;
importjava.util.concurrent.ScheduledExecutorService;
importjava.util.concurrent.TimeUnit;
publicclassScheduledExecutorTestimplementsRunnable{
privateStringjobName="";
publicScheduledExecutorTest(StringjobName){
super();
this.jobName=jobName;
}
@Override
publicvoidrun(){
System.out.println("execute"+jobName);
}
publicstaticvoidmain(String[]args){
ScheduledExecutorServiceservice=Executors.newScheduledThreadPool(10);
longinitialDelay1=1;
longperiod1=1;
//从现在开始1秒钟之后,每隔1秒钟执行一次job1
service.scheduleAtFixedRate(
newScheduledExecutorTest("job1"),initialDelay1,
period1,TimeUnit.SECONDS);
longinitialDelay2=1;
longdelay2=1;
//从现在开始2秒钟之后,每隔2秒钟执行一次job2
service.scheduleWithFixedDelay(
newScheduledExecutorTest("job2"),initialDelay2,
delay2,TimeUnit.SECONDS);
}
}
/**
结果:
executejob2
executejob1
executejob1
executejob2
executejob1
executejob2
*/
Calendar
实现复杂任务调度
Java代码测试Calendar
packagecom.zx.scheduler;
importjava.util.Calendar;
importjava.util.Date;
importjava.util.TimerTask;
importjava.util.concurrent.Executors;
importjava.util.concurrent.ScheduledExecutorService;
importjava.util.concurrent.TimeUnit;
publicclassScheduledExceutorTest2extendsTimerTask{
privateStringjobName="";
publicScheduledExceutorTest2(StringjobName){
super();
this.jobName=jobName;
}
@Override
publicvoidrun(){
System.out.println("Date="+newDate()+",execute"+jobName);
}
/**
*计算从当前时间currentDate开始,满足条件dayOfWeek,hourOfDay,
*minuteOfHour,secondOfMinite的最近时间
*@return
*/
publicCalendargetEarliestDate(CalendarcurrentDate,intdayOfWeek,
inthourOfDay,intminuteOfHour,intsecondOfMinite){
//计算当前时间的WEEK_OF_YEAR,DAY_OF_WEEK,HOUR_OF_DAY,MINUTE,SECOND等各个字段值
intcurrentWeekOfYear=currentDate.get(Calendar.WEEK_OF_YEAR);
intcurrentDayOfWeek=currentDate.get(Calendar.DAY_OF_WEEK);
intcurrentHour=currentDate.get(Calendar.HOUR_OF_DAY);
intcurrentMinute=currentDate.get(Calendar.MINUTE);
intcurrentSecond=currentDate.get(Calendar.SECOND);
//如果输入条件中的dayOfWeek小于当前日期的dayOfWeek,则WEEK_OF_YEAR需要推迟一周
booleanweekLater=false;
if(dayOfWeekweekLater=true;
}elseif(dayOfWeek==currentDayOfWeek){
//当输入条件与当前日期的dayOfWeek相等时,如果输入条件中的
//hourOfDay小于当前日期的
//currentHour,则WEEK_OF_YEAR需要推迟一周
if(hourOfDayweekLater=true;
}elseif(hourOfDay==currentHour){
//当输入条件与当前日期的dayOfWeek,hourOfDay相等时,
//如果输入条件中的minuteOfHour小于当前日期的
//currentMinute,则WEEK_OF_YEAR需要推迟一周
if(minuteOfHourweekLater=true;
}elseif(minuteOfHour==currentSecond){
//当输入条件与当前日期的dayOfWeek,hourOfDay,
//minuteOfHour相等时,如果输入条件中的
//secondOfMinite小于当前日期的currentSecond,
//则WEEK_OF_YEAR需要推迟一周
if(secondOfMiniteweekLater=true;
}
}
}
}
if(weekLater){
//设置当前日期中的WEEK_OF_YEAR为当前周推迟一周
currentDate.set(Calendar.WEEK_OF_YEAR,currentWeekOfYear+1);
}
//设置当前日期中的DAY_OF_WEEK,HOUR_OF_DAY,MINUTE,SECOND为输入条件中的值。
currentDate.set(Calendar.DAY_OF_WEEK,dayOfWeek);
currentDate.set(Calendar.HOUR_OF_DAY,hourOfDay);
currentDate.set(Calendar.MINUTE,minuteOfHour);
currentDate.set(Calendar.SECOND,secondOfMinite);
returncurrentDate;
}
publicstaticvoidmain(String[]args)throwsException{
ScheduledExceutorTest2test=newScheduledExceutorTest2("job1");
//获取当前时间
CalendarcurrentDate=Calendar.getInstance();
longcurrentDateLong=currentDate.getTime().getTime();
System.out.println("CurrentDate="+currentDate.getTime().toString());
//计算满足条件的最近一次执行时间
CalendarearliestDate=test
.getEarliestDate(currentDate,3,16,38,10);
longearliestDateLong=earliestDate.getTime().getTime();
System.out.println("EarliestDate="
+earliestDate.getTime().toString());
//计算从当前时间到最近一次执行时间的时间间隔
longdelay=earliestDateLong-currentDateLong;
//计算执行周期为一星期
longperiod=7*24*60*60*1000;
ScheduledExecutorServiceservice=Executors.newScheduledThreadPool(10);
//从现在开始delay毫秒之后,每隔一星期执行一次job1
service.scheduleAtFixedRate(test,delay,period,
TimeUnit.MILLISECONDS);
}
}
/**
输出结果:
CurrentDate=WedFeb0217:
32:
01CST2011
EarliestDate=TueFeb816:
38:
10CST2011
Date=TueFeb816:
38:
10CST2011,executejob1
Date=TueFeb1516:
38:
10CST2011,executejob1
*/
Quartz
Java代码测试quartz
packagecom.zx.scheduler;
importjava.util.Date;
importorg.quartz.Job;
importorg.quartz.JobDetail;
importorg.quartz.JobExecutionContext;
importorg.quartz.JobExecutionException;
importorg.quartz.Scheduler;
importorg.quartz.SchedulerFactory;
importorg.quartz.Trigger;
importorg.quartz.helpers.TriggerUtils;
publicclassQuartzTestimplementsJob{
@Override
//该方法实现需要执行的任务
publicvoidexecute(JobExecutionContextarg0)throwsJobExecutionException{
System.out.println("Generatingreport-"+arg0.getJobDetail().getFullName()+",type="+arg0.getJobDetail().getJobDataMap().get("type"));
System.out.println(newDate().toString());
}
publicstaticvoidmain(String[]args){
try{
//创建一个Scheduler
SchedulerFactoryschedFact=
neworg.quartz.impl.StdSchedulerFactory();
Schedulersched=schedFact.getScheduler();
sched.start();
//创建一个JobDetail,指明name,groupname,以及具体的Job类名,
//该Job负责定义需要执行任务
JobDetailjobDetail=newJobDetail("myJob","myJobGroup",QuartzTest.class);
jobDetail.getJobDataMap().put("type","FULL");
//创建一个每周触发的Trigger,指明星期几几点几分执行
Triggertrigger=TriggerUtils.makeWeeklyTrigger(2,17,47);//注意:
2,17,47表示的是周一17:
47执行任务
trigger.setGroup("myTriggerGroup");
//从当前时间的下一秒开始执行
trigger.setStartTime(TriggerUtils.getEvenSecondDate(newDate()));
//指明trigger的name
trigger.setName("myTrigger");
//用scheduler将JobDetail与Trigger关联在一起,开始调度任务
sched.scheduleJob(jobDetail,trigger);
}catch(Exceptione){
e.printStackTrace();
}
}
}
结果:
问题及方案:
使用Quartz时需要添加jar包,报此错误,缺少quartz-版本号.jar
例如:
quartz-1.5.2.jar
运行后:
报此错误:
缺少commons-logging.jar
Quartz整合spring
创建web工程:
itcast-quartz
Main类
packagecom.itcast.quartz;
importorg.springframework.context.support.ClassPathXmlApplicationContext;
publicclassMain{
publicstaticvoidmain(String[]args){
newClassPathXmlApplicationContext("classpath:
applicationContext-scheduler.xml");
}
}
MyJob类
packagecom.itcast.quartz;
importorg.quartz.JobExecutionContext;
importorg.quartz.JobExecutionException;
importorg.springframework.context.ApplicationContext;
importorg.springframework.scheduling.quartz.QuartzJobBean;
publicclassMyJobextendsQuartzJobBean{
@Override
protectedvoidexecuteInternal(JobExecutionContextcontext)
throwsJobExecutionException{
System.out.println("myJob执行了。
。
。
。
"+context.getTrigger().getKey().getName());
try{
ApplicationContextapplicationContext=(ApplicationContext)context.getJobDetail().getJobDataMap().get("applicationContext");
System.out.println("获取到的spring容器是"+applicationContext);
}catch(Exceptione){
System.out.println(e.getMessage());
e.printStackTrace();
System.out.println("出错了");
}
}
}
applicationContext-scheduler.xml
xmlversion="1.0"encoding="UTF-8"?
>
//www.springframework.org/schema/beans"
xmlns:
context="http:
//www.springframework.org/schema/context"
xmlns:
xsi="http:
//www.w3.org/2001/XMLSchema-instance"
x