zoukankan      html  css  js  c++  java
  • 任务调度中心 (普通版)【原】

    任务调度中心

    主要依赖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:	"+jobDetail);
    
            TriggerState  triggerState = scheduler.getTriggerState(new TriggerKey("trigger1","group1"));
            System.out.println("triggerState:	"+triggerState);
    View Code
  • 相关阅读:
    bzoj 1911: [Apio2010]特别行动队
    bzoj 1096: [ZJOI2007]仓库建设
    bzoj 3522: [Poi2014]Hotel
    bzoj 3572: [Hnoi2014]世界树
    bzoj 1177: [Apio2009]Oil
    bzoj 1912: [Apio2010]patrol 巡逻
    bzoj 3573: [Hnoi2014]米特运输
    bzoj 3997: [TJOI2015]组合数学
    cf 506 A. Mr. Kitayuta, the Treasure Hunter
    cf 500 D. New Year Santa Network
  • 原文地址:https://www.cnblogs.com/whatlonelytear/p/5650058.html
Copyright © 2011-2022 走看看