任务调度中心

主要依赖quartz.jar相关类 判断cron表达式 , 在下次即将执行的时间在指定时间内时, 从线程池中取线程进行调度 (普通版)

 

相关类

  1. MyTrigger.java (主入口)
  2. MyJob.java
  3. MyCallable.java

详细说明已都在java代码中体现.

相关jar包

quartz-2.2.3.zip

MyTrigger.java (主函数入口)



package com.testdemo.pcis.isc.job.king;

import java.text.SimpleDateFormat;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
/**
 * 触发器小例子.
 * 1. 模拟从数据库中取完整信息,得到cron表达式
 * 2. 判断时间是否在inSeconds(10)秒以内需要执行该任务
 * 3. 如果在inSeconds(10)秒以内,从线程池中启动新线程,发送数据
 * @author King
 * @time 2016/07/07
 */
public class MyTrigger {
    //指定任务处于inSeconds秒内时,就开启新线程任务
    private static final int inSeconds = 10;//秒
    //时间格式化器
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
    //线程池
    private static final ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);  
    
    public static void main(String[] args) throws Exception {
        // 模拟从数据库中取到一个与计划相关完整单行信息
        Object dataFromDb = new Object();
        
        // 模拟dataFromDb该行信息中cron表达式如下
        String cronArg = "50 45 14 * * ?";
        
        // 得到计划scheduler
        Scheduler scheduler = new StdSchedulerFactory().getScheduler();

        // 创建工作任务job
        JobDetail job = JobBuilder.newJob().ofType(MyJob.class)
                .withIdentity("job1", "group1").build();

        // 创建触发器trigger
        // 如果cronArg表达式不正确,会报java.text.ParseException,可以用来判断前台页面插入的cron表达式是否合法
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1").startNow()
                // .withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(10,2))
                .withSchedule(CronScheduleBuilder.cronSchedule(cronArg))
                // .withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule().withIntervalInHours(2))
                .build();
        
        // 对该计划指定运行 的工作任务和触发器,该行一定要有,不然触发器的下次执行时间会为null
        scheduler.scheduleJob(job, trigger);

        // 开始计划的执行,但这里最终目的只需要得到下次执行时间,而不需要真正执行,不然会启动线程增加性能消耗
         //s.start();

        //判断触发器trigger的下次执行时间是否临近
        boolean flag = nearToRun(trigger);
        
        //如果临近,那么开启新线程
        if(flag){
            startNewThread(trigger,dataFromDb);
        }
            
        
        
        // 关闭计划scheduler
//        s.shutdown(true);
    }
    
    /**
     * 判断触发器trigger的下次执行时间是否临近inSeconds秒以内(目前为10秒以内)
     * @param trigger
     * @return
     */
    public static boolean nearToRun(Trigger trigger){
        // 打印下次执行时间,得到结果
        System.out.println("trigger下次触发时间:" + sdf.format(trigger.getNextFireTime()));
        // 获取时差 = 该任务下次执行时间 - 当前时间
        long delayTimeMillis =  trigger.getNextFireTime().getTime() - System.currentTimeMillis();
        // 如果 0秒<时差<10秒 ,那么启动线程(这个10秒到时由properties.参数决定)
        if (delayTimeMillis > 0 && delayTimeMillis < inSeconds * 1000) {
            return true;
        }else{
            return false;
        }
    }
    
    
    /**
     * 从线程池开启新线程
     * @param trigger 触发器
     * @param dataFromDb 从数据库中取到的单行完整信息
     * @throws Exception
     */
    public static void startNewThread(Trigger trigger,Object dataFromDb) throws Exception{
        //模拟从数据库中取到的数据dataInDb
        UUID uuid = UUID.randomUUID();
        Callable<String> call = new MyCallableImpl(uuid.toString(),dataFromDb);
        // 再次获取时差,因为离executor.schedule(arg...)越近,越精确
        long delayTimeMillis2 =  trigger.getNextFireTime().getTime() - System.currentTimeMillis();
        Future future = executor.schedule(call, delayTimeMillis2,TimeUnit.MILLISECONDS);
        //如果1 * 3600 * 1000 = 1小时内还得不到返回信息就会报java.util.concurrent.TimeoutException,该参数从dataFromDb中提取
        String result = (String) future.get( 1 * 3600 * 1000,TimeUnit.MILLISECONDS);
        System.out.println("刚才启动的线程结束了,返回信息为:" + result);
    }

}



 

 

MyJob.java

为了触发器而创建的类,实际情况并不会运行,但仍旧依赖该job,只要有一个空实现即可.



package com.testdemo.pcis.isc.job.king;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

/**
 * Job实现类
 * @author King
 * @time 2016/07/07
 */
public class MyJob implements Job { 

    @Override 
    public void execute(JobExecutionContext arg0) throws JobExecutionException { 
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); 
        System.out.println(sdf.format(new Date())+"I'm runing");
        try {
            Thread.currentThread().sleep(1*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(sdf.format(new Date())+"I'm runing"); 
    } 
 
}



 

 

MyCallable

相当于线程的Runnable,实现类似于run()的call()方法,对真实业务进行调用



package com.testdemo.pcis.isc.job.king;

import java.util.concurrent.Callable;

/**
 * Callable实现类
 * @author King
 * @time 2016/07/07
 */
class MyCallable implements Callable<String> {
    private Object dataFromDb;
    public String name;

    public MyCallable() {
        super();
    }

    public MyCallable(String name, Object dataFromDb) {
        this.name = name;
        this.dataFromDb = dataFromDb;
    }

    @Override
    public String call() throws Exception {
        System.out.println("CallableImpl:" + name + " is start");
        // 把dataFromDb数据发送给指定URL,dataFromDb本身包含了URL地址,及超时时间等重要信息
        // send(dataFromDb)/自定义一个方法用于发送
        // 模拟发送情况,睡一会
        Thread.sleep(3 * 1000);
        System.out.println("CallableImpl:" + name + "is end");
        // 返回相关信息
        return "success";
    }
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Object getDataFromDb() {
        return dataFromDb;
    }

    public void setDataFromDb(Object dataFromDb) {
        this.dataFromDb = dataFromDb;
    }
}



 

 

其它无关tips

得到一些job和trigger的状态



JobDetail jobDetail = scheduler.getJobDetail(new JobKey("job1","group1"));
        System.out.println("jobDetail:\t"+jobDetail);

        TriggerState  triggerState = scheduler.getTriggerState(new TriggerKey("trigger1","group1"));
        System.out.println("triggerState:\t"+triggerState);


View Code