任务调度与异步执行器

时间:2021-09-27 19:59:05
任务调度与异步执行器:
 
 1、任务调度
          时间上的调度:特定时间执行指定的操作,如生成精华文章,统计记分排名,锁定用户
          资源调度:对使用资源进行控制
 
         涉及内容:
          多线程并发,运行时间规则定义,运行现场保持和恢复,线程池维护。
 
 
 2、实现方式:

  a、自定义多线程实现(难度太大)
  b、jdk1.3开始,通过java.util.Timer和TimerTask提供了简单的调用功能,允许用户调度一个按照固定周期运行的任务。
  c、jdk5.0通过java.util.concurrent新包中的若干接口,提供了方便的线程池使用。
  d、使用Quarz来实现任务调度功能
 
  注意:Spring对b,c,d三种方式都提供了支持,并不是自己实现了整个任务调度的功能,只是进行了封装,方便与spring进行整合,使用bean配置的方式,更易于程序开发。
 

3、Quartz概述:

 
  3.1 功能简介:
  灵活的定义触发器的调度时间表,并与任务进行关联映射。
  良好的现场恢复功能。
 
            3.2核心概念与接口:
                 
                  Scheduler内部组件结构图:
  任务调度与异步执行器

                任务:
   描述:要执行的具体操作。
   核心API:
   Job接口:定义要执行的任务,JobExecutieonContext中保存了调度上下文中的数据:
   public void execute(JobExecutionContext context);
   JobDetail接口:用来描述任务的详细信息,包括Job名称,监听器,描述,还有Job的具体实现类,这样方便运行时通过反射来执行Job,
   JobDetailImple:JobDetail实现类
              

                触发器:
                       描述:触发任务执行的规则,多为时间规则。
   核心API:
    Trigger类:定义触发任务执行的时间规则,主要用器两个子类:
    SimpleTrigger类:触发一次,或者按照固定间隔周期性执行
    CronTrigger类:复杂的时间触发,通过Cron表达式来定义,支持日历相关的时间间隔规则,而不是简单的周期性间隔。
    Calender类:一些特定日历的时间点的集合
   
                  调度器:
                       描述:quartz运行的独立容器,任务调度时,相关的任务,触发器,日历都需要注册到调度器中,运行时通过调度器来调度执行。调度器中的对象通过组和名称来确定唯一性。
   
   核心API:
    Scheduler接口:使用Scheduler中的接口,通过组和名称可以访问到调度器内的任务和触发器,并实现他们之间的绑定后,当触发器触发时,任务就会执行。
    SchdeulerFactory类:调度器工厂用来创建一个调度器,每个调度器都拥有自己的SchedulerContext,触发器和任务都可以访问SchedulerContext中的信息
   
                  线程池:
                           任务通过共享线程池内的线程提高运行效率。
   

                  其他API:
                           Quartz提供了构建器风格的api,对于调度器中的实体,都可以通过对应的构建器进行实例化,如:
                        JobBuilder:用来构建JobDetail实体对象:
                               JobDetail jobDetail=JobBuilder.newJob(SimpleJob.class)
                                   .withIdentity("MyJob1", "MyJobs")
                                   .build();//构建任务
   
                       TriggerBuilder:用来构建Trigger对象:
 SimpleTrigger trigger=TriggerBuilder.newTrigger()
      .withIdentity("trigger1", "myTriggers").startNow()
      .withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(10))
      .build();
 
                       ScheduleBuilder:用来构建一个计划,与触发器绑定:
                                 SimpleScheduleBuilder.repeatSecondlyForTotalCount(10)
 

   创建一个调度器,并调度任务:
    SchedulerFactory fac=new StdSchedulerFactory();
    Scheduler scheduler=fac.getScheduler();
    scheduler.scheduleJob(jobDetail, trigger);
    scheduler.start();
 
                
 
                         注意:
                           一个任务可以绑定多个触发器,一个触发器只能对应一个任务。
                            每个调度器(scheduler)中都有一个调度上下文,(schedulContext),其中的信息为调度其中的对象所共有共享。任务    (jobDetail)和触发器(Trigger)除共享schedulerContext中的数据外,本身都拥有一个JobDataMap对象,用来存放任务或者触发器本身的数据,对于无状态(没有实现StatfulJob接口)的任务还有触发器,在每次执行过程中都可以访问JobDataMao内的数据,但是执行中对JobDataMap中的数据修改,不会影响下次的执行,即他们拥有的是自己JobDataMap对象的复制对象。
   
 
                        Cron表达式:用来构建复杂的CronTrigger,Cron表达式有6或者7位从左到右的字符组成,有空格隔开:

Cron表达式时间字段
位置(从左到右)
表示时间
允许值范围
允许特殊字符
1
0-59
*,-/
2
分钟
0-59
*,-/
3
小时
0-23
*,-/
4
日期
1-31
*,-/?LWC
5
月份
1-12
*,-/
6
星期
1-7(7是星期六)
*,-/?LC#
7
年份
空值或1970-2099 *-,/
 
          特殊字符的意义( 在对应的字段的时间范围内):
                *: 对应时间范围的每一个时刻,如在分钟字段中,则表示“每分钟”
                ?:无意义,占位符, 只能用在日期和星期字段中
                -:在对应时间域中表示一个范围,如小时中12-13表示12点到13点钟
                ,:表示一个列表,如MON,WEN比表示星期一和星期三
                /:x/y表示一个等步长序列,x为起始值,y为步长
                L:Last的意思, 只在日期和星期中使用,最后月中最后一天,或者一周中最后一天, 一周内最后一天是星期六,值是7。L前面有数值时表示,最后第几天,如5L
               W: 只能在日期字段内,表示最近的工作日,如15W表示该月内15号最近的工作日,匹配不能跨月,有连个最近天时往后推。
                LW: 日期字段中,当月最后一个工作日。
                #: 星期字段中使用,当月某一个工作日,如6#3,6是星期五,表示当月第3个星期五,当月如果没有则不处罚。
                C: 只在日期和星期字段中使用,关联某一个日期或星期,如日期字段中10C,表示当月10号后的第一天,星期字段中2C表示星期一后的第一天。
            

            Cron表达式对特殊字符的大小写不敏感,对代表星期的缩写英文大小写也不敏感。

            Cron表示式示例

表示式

说明

"0 0 12 * * ? "

每天12点运行

"0 15 10 ? * *"

每天10:15运行

"0 15 10 * * ?"

每天10:15运行

"0 15 10 * * ? *"

每天10:15运行

"0 15 10 * * ? 2008"

2008年的每天1015运行

"0 * 14 * * ?"

每天14点到15点之间每分钟运行一次,开始于14:00,结束于14:59

"0 0/5 14 * * ?"

每天14点到15点每5分钟运行一次,开始于14:00,结束于14:55

"0 0/5 14,18 * * ?"

每天14点到15点每5分钟运行一次,此外每天18点到19点每5钟也运行一次。

"0 0-5 14 * * ?"

每天14:00点到14:05,每分钟运行一次。

"0 10,44 14 ? 3 WED"

3月每周三的14:10分到14:44,每分钟运行一次。

"0 15 10 ? * MON-FRI"

每周一,二,三,四,五的10:15分运行。

"0 15 10 15 * ?"

每月1510:15分运行。

"0 15 10 L * ?"

每月最后一天10:15分运行。

"0 15 10 ? * 6L"

每月最后一个星期五10:15分运行。

"0 15 10 ? * 6L 2007-2009"

2007,2008,2009年每个月的最后一个星期五的10:15分运行。

"0 15 10 ? * 6#3"

每月第三个星期五的10:15分运行。


        日历使用:
                实际调度中,有时不能不变的按照特定周期调度人物,必须考虑到一些特殊的日期,要排除,则需使用Quartz中的日历,某些特定时间的集合,
                Calendar提供了一些常用的日历实现类,来表示特定的日期:
                
        3.3、任务调度信息存储
                    一般情况下,任务的调度信息存储在内存中,如调度次数,第几次等调度, JobDataMap中的数据等相关信息。这样数据访访问快,但是由于数据没有持久化保存,当系统崩溃时,所有运行时信息丢失,调度现场无法还原。

                 配置任务调度信息的保存策略:
                       


4、Spring集成Quartz
            Spring为创建JobDetail、Scheduler、Trigger等调度器实体,提供了便利的FactoryBean,方便Spring容器的管理,并提供了一些工具类, 可以将Spring中的Bean封装成任务,对Quartz进行了封装,能以更具Spring风格的使用Quartz。
            主要有两个方面的支持:
                    1、提供良好的BeanFactory类,在Spring环境中创建Quartz任务调度中对应的组件对象, 并结合Spring容器的生命周期进行调度的启动和停止
                    2、为Quartz重要的组件对象提供更具Bean风格的扩展类。

             Spring对Quartz的扩展
           
                     JobDetailBean:对JobDetail的扩展,更具Bean风格的扩展。直接创建JobDetail只能通过爱参数的构造函数。
                    全称:org.springframework.scheduling.quartz.JobDetailBean。
                    常见属性配置:
                             jobClass:Job接口的任务类,class类型
                             beanName:默认为bean的id名,对应任务名,不指定组则是默认组
                             JobDataAsMap:map类型,任务对应提供数据的JobDataMap
                             applicationContextJobDataKey:是否将spring的applicationContext保存到任务的JobDataMap中,给属性指定key,无该属性在不保存。
                            JobListenNames:String数组类型,指定注册在Scheduler中的jobListeners名臣。

                    
                     
                MethodInvokingJobDetailFactoryBean: 生成任务的BeanFactory,能够方便的将Spring中的bean的某一个方法,封装成满足Quartz要求的Job,
                        全称: org.springframework.scheduling.quartz. MethodInvokingJobDetailFactoryBean
                        常见属性配置:
                                targetObject:引用哪个bean
                                targetMethod:指定bean的哪个方法
                                concurrent:任务是有状态任务,还是无状态任务


                   
                  SimpleTriggerBean :SimpleTrigger的扩展类,在Spring以bean的方式记性配置。
                           全称:   org.springframework.scheduling.quartz.SimpleTriggerBean
                           常见属性配置:
                                    jobDetail:对应的Spring中的任务
                                    jobDataAsMap:trigger中的jobDataMap提供值,map类型
                                    startDelay:延时多少时间开始触发。

                     
                CronTriggerBean :CronTrigger的扩展
                            全称: org.springframework.scheduling.quartz. CronTriggerBean
                             常见属性配置:
                                    jobDetail:对应的Spring中的任务
                                    jobDataAsMap:trigger中的jobDataMap提供值,map类型
                                    cronExpression:cron表达式

                   
                 SchedulerFactoryBean :用来创建Quartz的调度器。
                            全称: org.springframework.scheduling.quartz. CronTriggerBean
                            主要功能:
                                    1、以更具bean风格的方式,创建Scheduler,并提供配置信息
                                    2、让Scheduler和Spring容器的生命周期建立关联,相生相息
                                    3、通过属性配置方式替换Quartz的zisheg
                            常见配置:
                                    JobDetails:类型为JobdDetailBean[],往调度器里面注册的JobDetail
                                    triggers:类型TriggerBean[],往调度器内注册trigger
                                    shedulerContextAsMap:map类型,往SchedulerContext内设置数据
                                    autoStartup: SchedulerFactoryBean初始化后是否马上启动Scheduler,默认true
                                    startupDelay: SchedulerFactoryBean初始化后,延时多少启动 Scheduler。
                                    quartzProperties:Properties类型,覆盖Quartz的默认配置
                                    configLocaion:显示执行quartz的配置文件
    
    注意:静态变量是ClassLoader级别的,当Web应用程序停止时,静态变量会从JVM中清楚 ,但是线程则是JVM级别的,如果用户在Web应用中启动了一个线程,这个线程的生命周期不会和Web应用程序保持同步,只要JVM不关闭,即使关闭了Web应用,线程依然是活跃。 当我们手动使用JDK Timer或者Quart进行任务调度时,在Web引用关闭时,要手动停止调度Spring为我们提供了用于创建Quartz Scheduler和JDK Timer基础设施的Factory,可以保证Quartz和JDK Timer调度线程在Spring 容器关闭时自动停止。