全面解析JAVA中的任务调度机制

任务调度 是指基于给定时间点,给定时间间隔或者给定执行次数自动执行任务。
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/

你可能感兴趣的:(Java)