JAVAにおけるタスクスケジューリングメカニズムを全面的に解析する

7043 ワード

タスクスケジューリング
指定された時点、指定された間隔、または指定された実行回数に基づいて自動的にタスクを実行することを意味します.
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の利点は簡単で使いやすいことですが、
すべてのタスクは同じスレッドでスケジューリングされるため、すべてのタスクはシリアルで実行され、同じ時間に1つのタスクしか実行されず、前のタスクの遅延や異常は後のタスクに影響します.
例:
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はスレッドを実際に起動し、残りの時間はタスクをポーリングしている状態であることに注意してください. ScheduledExecutorServiceで最も一般的な2つのスケジューリング方法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は強力なオープンソースタイミングスケジューラで、主に4つの部分から構成されています.
1、Jobは仕事、つまり具体的に実行するコンテンツインタフェースを表し、このインタフェースには一つの方法しかない.
void execute(JobExecutionContext context)
2、JobDetailは具体的な実行可能なスケジューラを表し、Jobはこの実行可能なスケジューラが実行する内容である.さらにJobDetailには、このタスクスケジューリングのシナリオとポリシーも含まれています.
3.Triggerトリガは、タスクスケジュールの時間と間隔、頻度などを定義するために使用されます.
4、Schedulerは1つのスケジューリングコンテナを表し、1つのスケジューリングコンテナは複数のJobDetailとTriggerを登録することができる.そしてそれらを組み合わせることでSchedulerコンテナでスケジューリングできます.
Quartz全体の動作原理は、Schedulerというコンテナを通じて多くのJobDetailとTriggerを格納し、コンテナが起動すると、Triggerによって自動的にトリガされて対応するJobDetailを実行することである.
JobDetail自体は実行可能な仕事であり、TriggerはシステムがいつどのようなポリシーでJobDetail実行を呼び出すかを制御し、Schedulerの役割はそれら2つを組み立てるだけだ.
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/