任务调度
是指基于给定时间点,给定时间间隔或者给定执行次数自动执行任务。
JAVA中的任务调度主要包含以下3种:
1、Timer
2、ScheduledExecuror
3、开源工具包Quartz
一、Timer
java.util.Timer是一种最简单的任务调度机制,使用 Timer 实现任务调度的核心类是 Timer 和 TimerTask。 其中 Timer 负责设定 TimerTask 的起始与间隔执行时间。使用者只需要创建一个 TimerTask 的继承类,
实现自己的 run 方法,然后将其丢给 Timer 去执行即可。
Timer 的设计核心是一个 TaskList 和一个 TaskThread。 Timer 将接收到的任务丢到自己的 TaskList中 ,
TaskList 按照 Task 的最初执行时间进行排序。TimerThread 在创建 Timer 时会启动成为一个守护线程。这个线程会轮询所有任务,找到一个最近要执行的任务,然后休眠,
当到达最近要执行任务的开始时间点,TimerThread 被唤醒并执行该任务。之后 TimerThread 更新最近一个要执行的任务,继续休眠。Timer 的优点在于简单易用,但由于
所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务。
例子:
package com.lza.taskSchedule;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class TimerTest extends TimerTask{
private String jobName="";
public TimerTest(String jobName){
super();
this.jobName=jobName;
}
@Override
public void run(){//覆写执行方法
System.out.println("execute "+jobName+new Date());
}
public static void main(String[] args){
Timer timer=new Timer();
long delay1=1*1000;
long period1=1000;
timer.schedule(new TimerTest("Job1"),delay1,period1);//从现在开始 1 秒后 每隔1秒 执行1次Job1
long delay2=2*1000;
long period2=2000;
timer.schedule(new TimerTest("Job2"),delay2,period2);//从现在开始 2 秒后 每隔2秒 执行1次Job2
}
}
二、ScheduledExecutor
ScheduledExecutor的设计思想是:每一个被调度的任务都会由线程池中一个线程去执行,因此任务是并发执行的,相互之间不会受到干扰。需要注意的是,只有当任务的执行时间到来时,ScheduedExecutor 才会真正启动一个线程,其余时间 ScheduledExecutor 都是在轮询任务的状态。 ScheduledExecutorService 中两种最常用的调度方法 ScheduleAtFixedRate 和 ScheduleWithFixedDelay。
ScheduleAtFixedRate 每次执行时间为上一次任务开始起向后推一个时间间隔,即每次执行时间为 :initialDelay, initialDelay+period, initialDelay+2*period, …; ScheduleWithFixedDelay 每次执行时间为上一次任务结束起向后推一个时间间隔,即每次执行时间为:initialDelay, initialDelay+executeTime+delay, initialDelay+2*executeTime+2*delay。
ScheduleAtFixedRate 是基于固定时间间隔进行任务调度, ScheduleWithFixedDelay 取决于每次任务执行的时间长短,是基于不固定时间间隔进行任务调度。
例子:
package com.lza.taskSchedule;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledExecutorTest implements Runnable {
private String jobName = "";
public ScheduledExecutorTest(String jobName) {
super();
this.jobName = jobName;
}
@Override
public void run() {
System.out.println("execute " + jobName);
}
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
long delayTime = 1;
long period = 1;
// 从现在开始1秒钟之后,每隔1秒钟执行一次job1
service.scheduleAtFixedRate(//固定时间间隔
new ScheduledExecutorTest("job1"), delayTime,
period, TimeUnit.SECONDS);
long delayTime2 = 2;
long period2 = 2;
// 从现在开始2秒钟之后,每隔2秒钟执行一次job2
service.scheduleWithFixedDelay(//不固定时间间隔
new ScheduledExecutorTest("job2"), delayTime2,
period2, TimeUnit.SECONDS);
}
}
三、开源工具包Quartz
Quartz是一个强大的开源定时调度器,它主要由四部分构成:
1、Job 表示工作也就是具体要执行的内容接口,这个接口只有一个方法
void execute(JobExecutionContext context)
2、JobDetail 表示一个具体的可执行的调度程序,而Job就是这个可执行调度程序所要执行的内容。另外JobDetail还包含了这个任务调度的方案和策略。
3、Trigger 触发器 用来定义任务调度的时间与间隔、频率等。
4、Scheduler 代表一个调度容器,一个调度容器可以注册多个JobDetail和Trigger。然后将它们组合在一起就可以用Scheduler容器进行调度了。
整个Quartz的工作原理就是通过Scheduler这个容器去存储众多的JobDetail和Trigger,当容器启动后,由Trigger自动触发 去执行相应的JobDetail
JobDetail本身就是一个可以执行的工作,Trigger则控制系统什么时候 按什么策略去调用JobDetail执行,而Scheduler的作用只是把它们两个组装在一起。
在Scheduler这个容器中,通过线程池去对各个Job进行并行调度,提高容器的工作效率。
例子:
package com.lza.taskSchedule;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* 构建一个Job类 这个类就是任务具体执行的操作类
* @author Administrator
*
*/
public class TimerJob implements Job{
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// TODO Auto-generated method stub
System.out.println("Generating report - "
+ context.getJobDetail().getFullName() + ", "
+ context.getJobDetail().getJobDataMap().get("name")
+ context.getJobDetail().getJobDataMap().get("age"));
System.out.println(new Date().toString());
}
}
package com.lza.taskSchedule;
import java.util.Map;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzManager {
private Scheduler scheduler;
private final static String JOB_GROUP_NAME="TestJob";
private final static String TRIGGER_GROUP_NAME="TestTrigger";
private static QuartzManager instance = new QuartzManager();
public static QuartzManager getInstance(){
return instance;
}
public void init( ){
try {
scheduler=new StdSchedulerFactory().getScheduler();
scheduler.start();
} catch (SchedulerException e) {
System.out.println("schedule start fail:"+e);
}
}
public QuartzManager(){
init();
}
public boolean addJob(String jobName, String jobClass, String time ,Map params) {
boolean result = false;
try {
JobDetail jobDetail = new JobDetail(jobName, JOB_GROUP_NAME, Class.forName(jobClass));// 任务名,任务组,任务执行类
jobDetail.getJobDataMap().putAll(params);
// 触发器
CronTrigger trigger = new CronTrigger(jobName, TRIGGER_GROUP_NAME);// 触发器名,触发器组
trigger.setCronExpression(time);// 触发器时间设定
if(scheduler.isShutdown()){
init( );
}
scheduler.scheduleJob(jobDetail, trigger);
result = true;
} catch (Exception e) {
result = false;
System.out.println("schedule addJob fail jobName = " + jobName + ". time = " + time + ". jobClass = " + jobClass);
}
return result;
}
}
package com.lza.taskSchedule;
import java.util.HashMap;
import java.util.Map;
public class QuartzTest {
public static void main(String args[]){
//TestJob testJob=new TestJob("Hello",21);
Map testMap=new HashMap();
testMap.put("name", "Hello");
testMap.put("age", 21);
boolean result=QuartzManager.getInstance().addJob("testId",TimerJob.class.getName() ,"0 36 15 28 10 ?", (Map)testMap);
System.out.println(result);
}
}
参考链接:https://www.ibm.com/developerworks/cn/java/j-lo-taskschedule/
http://lavasoft.blog.51cto.com/62575/181907/