zoukankan      html  css  js  c++  java
  • Quartz任务调度器

    原文地址:http://blog.csdn.net/liovey/article/details/8600719

    背景:
    近期项目中遇到跨区调拨商品的需求,比如A区和B区,需要判断A区或者B区某种sku是否需要从对方库调拨商品来补充货源,避免因缺失商品而出现订单延误,影响销售和对用户产生不良影响。

    问题:
    数据量庞大,如果当查看的时候去获取数据,那么会严重影响系统的性能,甚至导致数据库和应用服务器无法响应。

    解决方案:
    规定在某个时间点,最好是在晚上12点时系统自动获取需要调拨的数据,然后将数据存储到数据库中。晚上12点,用户访问量和系统的其它工作最少,这个时候启动一个定时线程来获取数据对系统的影响几乎没有。

    采用技术:
    Quartz,Quartz是一个开源的作业调度框架,它完全由Java写成,并设计用于J2SE和J2EE应用中。它提供了巨大的灵活性而不牺牲简单性。可以使用这个框架来完成定时任务的调度。

    使用步骤:
    1、编写业务处理模块。
    该模块针对本需求,首先获取近期需要调度的sku列表,这是比较耗时的,因为需要查看近20天的
    进销存记录并统计发货数量。
    其次判断发货量是否满足某种条件(条件为业务内容,条件准备比较复杂)来进行补货,当满足时,查看其它库区同种sku是否满足调拨条件。
    再次记录两库的日均发货量。
    当上述条件满足时,生成数据,如果不满足则跳过,进行下一个sku判断,直到所有sku处理完毕。

    Demo:
    业务处理模块:

    package com.tgb.test;
    
    public class BusinessJob {
    
        public void generateBusinessInfo(){
            System.out.println("业务数据产生完毕!");
        }
    }

    定时任务模块:

    package com.tgb.test;
    
    import org.quartz.Job;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    
    public class TimeJob implements Job {    
        
        //重写方法
        public void execute(JobExecutionContext context)throws JobExecutionException {  
            BusinessJob businessJob = new BusinessJob();  
            businessJob.generateBusinessInfo();
        }  
    }

    定时调度模块:

    package com.tgb.test;
    
    import org.quartz.CronTrigger;
    import org.quartz.JobDetail;
    import org.quartz.Scheduler;
    import org.quartz.SchedulerException;
    import org.quartz.impl.StdSchedulerFactory;
    
    public class JobSchedule {
    
        private static Scheduler scheduler = null;
        private static final Object lock = new Object();
        
        
        public static Scheduler getSchedulerInstance(){
            if(scheduler == null){
                synchronized(lock){
                    if(scheduler == null){
                        try {
                            scheduler = StdSchedulerFactory.getDefaultScheduler();
                        } catch (SchedulerException e) {
                            return null;
                        }
                    }
                }
            }
            return scheduler;
        }
        
        /**
         * 添加任务
         * @param jobName任务名称
         * @param jobGroup任务组名称
         * @param jobClass任务类对象
         * @param cronExpress定时调度表达式
         */
        public void addJob(String jobName, String jobGroup, Class<?> jobClass, String cronExpress){
            
            try{
                JobDetail jobDetail = new JobDetail(jobName, jobGroup, jobClass);  
                //创建触发器对象,并为它设置名称,组名称,及任务调度的时间参数  
                CronTrigger cronTrigger = new CronTrigger("trigger1", "triggerGroup");  
                
                cronTrigger.setCronExpression(cronExpress);
                 //配置JobDetail和Trigger对象  
                JobSchedule.getSchedulerInstance().scheduleJob(jobDetail, cronTrigger);
            }catch(Exception e){
                throw new RuntimeException(e);
            }
        }
        
        /**
         * 启动调度器
         */
        public void startScheduler(){
            try{
                if(!JobSchedule.getSchedulerInstance().isStarted()){
                    JobSchedule.getSchedulerInstance().start();
                }
            }catch(Exception e){
                throw new RuntimeException(e);
            }
        }
        
        
        /**
         * 停止调度器
         */
        public void stopScheduler(){
            try{
                if(JobSchedule.getSchedulerInstance().isStarted()){
                    JobSchedule.getSchedulerInstance().shutdown(true);
                }
            }catch(Exception e){
                throw new RuntimeException(e);
            }
        }
    }

    主线程入口:

    package com.tgb.test;
    
    
    public class TestMain {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            
            //构造定时模块
            TimeJob timeJob = new TimeJob();  
            
            //构造调度管理者
            JobSchedule jobSchedule = new JobSchedule();
            
            //添加job
            jobSchedule.addJob("jobName", "jobGroup", timeJob.getClass(), "0 0 23 * * ?");
            
            //启动调度器
            jobSchedule.startScheduler();
            
            //关闭调度器
    //        jobSchedule.stopScheduler();
        }
    }

    控制台输出:

    任务调度表达式:

    “*”字符代表所有可能的值
    
    因此,“*”在子表达式(月)里表示每个月的含义,“*”在子表达式(天(星期))表示星期的每一天
    
    “/”字符用来指定数值的增量
    
    例如:在子表达式(分钟)里的“0/15”表示从第0分钟开始,每15分钟
    
             在子表达式(分钟)里的“3/20”表示从第3分钟开始,每20分钟(它和“3,23,43”)的含义一样
    
    “?”字符仅被用于天(月)和天(星期)两个子表达式,表示不指定值
    
    当2个子表达式其中之一被指定了值以后,为了避免冲突,需要将另一个子表达式的值设为“?”
    
     
    
    “L” 字符仅被用于天(月)和天(星期)两个子表达式,它是单词“last”的缩写
    
    但是它在两个子表达式里的含义是不同的。
    
    在天(月)子表达式中,“L”表示一个月的最后一天
    
    在天(星期)自表达式中,“L”表示一个星期的最后一天,也就是SAT
    
    如果在“L”前有具体的内容,它就具有其他的含义了
    
    例如:“6L”表示这个月的倒数第6天,“FRIL”表示这个月的最一个星期五
    
    注意:在使用“L”参数时,不要指定列表或范围,因为这会导致问题
    
    字段 允许值 允许的特殊字符 
    秒 0-59 , - * /0-59 , - * / 
    小时 0-23 , - * / 
    日期 1-31 , - * ? / L W C 
    月份 1-12 或者 JAN-DEC , - * / 
    星期 1-7 或者 SUN-SAT , - * ? / L C # 
    年(可选) 留空, 1970-2099 , - * / 
    
    
    表达式 意义 
    "0 0 12 * * ?" 每天中午12点触发 
    "0 15 10 ? * *" 每天上午10:15触发 
    "0 15 10 * * ?" 每天上午10:15触发 
    "0 15 10 * * ? *" 每天上午10:15触发 
    "0 15 10 * * ? 2005" 2005年的每天上午10:15触发 
    "0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发 
    "0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发 
    "0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 
    "0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发 
    "0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发 
    "0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发 
    "0 15 10 15 * ?" 每月15日上午10:15触发 
    "0 15 10 L * ?" 每月最后一日的上午10:15触发 
    "0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发 
    "0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发 
    "0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发 
    ===============================================================================
    
    秒(0~59)
    
    分钟(0~59)
    
    小时(0~23)
    
    天(月)(0~31,但是你需要考虑你月的天数)
    
    月(0~11)
    
    天(星期)(1~7 1=SUN 或 SUN,MON,TUE,WED,THU,FRI,SAT)
    
     
    
    一个完整的例子
    
    “0 0 12 ? * WED”表示每个星期三中午12点
    
     
    
    有些子表达式能包含一些范围或列表
    
    例如:子表达式(天(星期))可以为 “MON-FRI”,“MON,WED,FRI”,“MON-WED,SAT”

     这里没有配置quartz.properties文件,框架会读取jar包中的默认配置文件,默认开启的线程有10个,可以自己写个quartz.properties配置文件定义配置信息

  • 相关阅读:
    在IE和Firfox获取keycode
    using global variable in android extends application
    using Broadcast Receivers to listen outgoing call in android note
    help me!virtual keyboard issue
    using iscroll.js and iscroll jquery plugin in android webview to scroll div and ajax load data.
    javascript:jquery.history.js使用方法
    【CSS核心概念】弹性盒子布局
    【Canvas学习笔记】基础篇(二)
    【JS核心概念】数据类型以及判断方法
    【问题记录】ElementUI上传组件使用beforeupload钩子校验失败时的问题处理
  • 原文地址:https://www.cnblogs.com/vaer/p/3903555.html
Copyright © 2011-2022 走看看