任务调度器和异步执行器

1.quartz高度抽象为任务、触发器、调度器
任务:job提供需要执行的任务,程序员实现该接口,在执行job时每次都要创建一个job实例,所以jobdetail接收job的实现类创建实例。同时对job的描述也在jobdetail的构造函数中标明,如调度时的组名和job名称。
触发器:规定时间触发规则,有2个类SimpleTrigger(触发一次或固定间隔周期)CronTrigger(实现cron表达式实现复杂方案),其中Trigger可以和quartz定义的Calendar结合针对一些时间进行包含或者排除(与java原生态Calendar不一样),在org.quartz.implCalendar包下有多种实现类。
调度器(scheduler):它是quartz的独立运行容器,Trigger和Jobdetail可以注册到该容器中(有各自的组和名称),trigger的组和名称合起来必须唯一,同理jobdetail也是组和名称合起来必须为,因为类型不相同所以在2个不同集合中。将Trigger和jobdetail进行绑定实现功能执行,一个job对应多个trigger但是一个trigger只能对应一个job。SchedulerFactory创建scheduler实例,在scheduler中有一个schedulerContext,保存着上下文和servletContext类似。
线程池(ThreadPool):scheduler通过线程池对任务进行调用。


状态job:在job中有一个标签子接口(statefulJob)标注接口是有无状态,有状态job表示当次的执行将影响后面的job执行,无状态job则不会。再job中有一个JobDataMap保存着数据,无状态的每次会复制一个该对象,而有状态的会共享该对象。因此无状态可以并发执行,有状态的就需要等待。一般使用无状态job。如果quartz启动数据库持久化任务调度,则无状态的在注册时保存一次,有状态的每次执行都需要保存。
trigger也有自己的jobdatamap属性,但是每次启动时不会持久化到数据库中。


quartz事件机制:job执行前后,trigger触发前后,scheduler调度前后都可以注册事件进行监听。


2.与spring集成
JobDetailFactoryBean属性:
jobclass实现job的类
beanName默认是bean的id
jobDataAsMap给jobdatamap中输入值
applicationContextJobDataKey指定一个名词在job实现类中可以引用spring的应用上下文
jobListenerNames:指定监听的类名


MethodInvokingJobDetailFactoryBean(这种方式不能持久化)
可以实现把一个业务bean的某个方式封装成具有job实现类的形式提供给任务调度器(前提是这个方法不能有参数)


创建触发器bean简单
创建调度器和spring容器的生命周期进行了关联,并且代替了quartz自身的配置文件,可以自定义property配置文件,还有一些配置如:
calendars为调度器添加calendar
jobdetails向调度器添加jobdetail
autoStartup是否自动启动,不启动则需要程序中启动
starupDelay 延迟多少秒启动scheduler
package com.kay.quartz;
public class QuartzJob {
    public void work() {
        System.out.println("Quartz的任务调度!!!");
    }
}




<beans>    
        <!-- 要调用的工作类 -->
        <bean id="quartzJob" class="com.kay.quartz.QuartzJob"></bean>
        <!-- 定义调用对象和调用对象的方法 -->
        <bean id="jobtask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
            <!-- 调用的类 -->
            <property name="targetObject">
                <ref bean="quartzJob"/>
            </property>
            <!-- 调用类中的方法 -->
            <property name="targetMethod">
                <value>work</value>
            </property>
        </bean>
        <!-- 定义触发时间 -->
        <bean id="doTime" class="org.springframework.scheduling.quartz.CronTriggerBean">
            <property name="jobDetail">
                <ref bean="jobtask"/>
            </property>
            <!-- cron表达式 -->
            <property name="cronExpression">
                <value>10,15,20,25,30,35,40,45,50,55 * * * * ?</value>
            </property>
        </bean>
        <!-- 总管理类 如果将lazy-init='false'那么容器启动就会执行调度程序  -->
        <bean id="startQuertz" lazy-init="false" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
            <property name="triggers">
                <list>
                    <ref bean="doTime"/>
                </list>
            </property>
        </bean>
</beans>


测试程序:
    public static void main(String[] args) {
        System.out.println("Test start.");
        ApplicationContext context = new ClassPathXmlApplicationContext("quartz-config.xml");
        //如果配置文件中将startQuertz bean的lazy-init设置为false 则不用实例化
        //context.getBean("startQuertz");
        System.out.print("Test end..");
    }


参考:https://www.ibm.com/developerworks/cn/opensource/os-cn-quartz/

https://blog.csdn.net/u010648555/article/details/54863144

https://blog.csdn.net/Evankaka/article/category/3155529

3.jdk提供的timer和timertask类:timertask相当于任务,timer相当于调度器


timertask是一个虚类,需要继承重写(有3个重载方法)
timer只能在固定周期时间调用任务方法。所有的timertask都在该timer下执行所有有时候会出现延迟,因此需要每次执行的任务短。
如果要销毁timer需要使用cancel方法。
java线程分为用户线程和守护线程,垃圾回收器就是守护线程,主要是服务用户线程,当用户线程全部执行完成守护线程也会自动终止,设置线程我守护线程方法为:Thread.setDaemon(true);




4.Executor主要实现任务提交和任务执行解耦
http://blog.csdn.net/mack415858775/article/details/51508831
java通过Executors提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行


(1) newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。示例代码如下:
package test;  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
public class ThreadPoolExecutorTest {  
 public static void main(String[] args) {  
  ExecutorService cachedThreadPool = Executors.newCachedThreadPool();  
  for (int i = 0; i < 10; i++) {  
   final int index = i;  
   try {  
    Thread.sleep(index * 1000);  
   } catch (InterruptedException e) {  
    e.printStackTrace();  
   }  
   cachedThreadPool.execute(new Runnable() {  
    public void run() {  
     System.out.println(index);  
    }  
   });  
  }  
 }  
}
线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。


(2) newFixedThreadPool(项目用过)
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。示例代码如下:
package test;  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
public class ThreadPoolExecutorTest {  
 public static void main(String[] args) {  
  ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);  
  for (int i = 0; i < 10; i++) {  
   final int index = i;  
   fixedThreadPool.execute(new Runnable() {  
    public void run() {  
     try {  
      System.out.println(index);  
      Thread.sleep(2000);  
     } catch (InterruptedException e) {  
      e.printStackTrace();  
     }  
    }  
   });  
  }  
 }  
} 因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。
定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()


(3)  newScheduledThreadPool
创建一个定长线程池,支持定时及周期性任务执行。延迟执行示例代码如下:
package test;  
import java.util.concurrent.Executors;  
import java.util.concurrent.ScheduledExecutorService;  
import java.util.concurrent.TimeUnit;  
public class ThreadPoolExecutorTest {  
 public static void main(String[] args) {  
  ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);  
  scheduledThreadPool.schedule(new Runnable() {  
   public void run() {  
    System.out.println("delay 3 seconds");  
   }  
  }, 3, TimeUnit.SECONDS);  
 }  

表示延迟3秒执行。
定期执行示例代码如下:
package test;  
import java.util.concurrent.Executors;  
import java.util.concurrent.ScheduledExecutorService;  
import java.util.concurrent.TimeUnit;  
public class ThreadPoolExecutorTest {  
 public static void main(String[] args) {  
  ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);  
  scheduledThreadPool.scheduleAtFixedRate(new Runnable() {  
   public void run() {  
    System.out.println("delay 1 seconds, and excute every 3 seconds");  
   }  
  }, 1, 3, TimeUnit.SECONDS);  
 }  
}  
表示延迟1秒后每3秒执行一次


(4) newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。示例代码如下:
package test;  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
public class ThreadPoolExecutorTest {  
 public static void main(String[] args) {  
  ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();  
  for (int i = 0; i < 10; i++) {  
   final int index = i;  
   singleThreadExecutor.execute(new Runnable() {  
    public void run() {  
     try {  
      System.out.println(index);  
      Thread.sleep(2000);  
     } catch (InterruptedException e) {  
      e.printStackTrace();  
     }  
    }  
   });  
  }  
 }  



结果依次输出,相当于顺序执行各个任务。




单独使用timer、quartz、executor创建的线程默认是非守护线程,在程序结束后任然会继续执行,如果使用spring注入将这些调度开启和关闭与spring容器进行关联,spring容器启动调度任务开始,应用程序结束(spring容器关闭)调度任务停止。
创建的静态成员是classloader级别,如果web程序停止这些变量会从JVM中删除,而线程是JVM级别,如果在应用程序中启动线程在应用程序关闭后并不会回收该线程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
XXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。 XXL-JOB特点: 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; 2、动态:支持动态修改任务状态、启动/停止任务,以及终止运行中任务,即时生效; 3、调度中心HA(中心式):调度采用中心式设计,“调度中心”自研调度组件并支持集群部署,可保证调度中心HA; 4、执行器HA(分布式):任务分布式执行,任务"执行器"支持集群部署,可保证任务执行HA; 5、注册中心: 执行器会周期性自动注册任务, 调度中心将会自动发现注册的任务并触发执行。同时,也支持手动录入执行器地址; 6、弹性扩容缩容:一旦有新执行器上线或者下线,下次调度时将会重新分配任务; 7、路由策略:执行器集群部署时提供丰富的路由策略,包括:第一个、最后一个、轮询、随机、一致性HASH、最不经常使用、最近最久未使用、故障转移、忙碌转移等; 8、故障转移:任务路由策略选择"故障转移"情况下,如果执行器集群中某一台机故障,将会自动Failover切换到一台正常的执行器发送调度请求。 9、阻塞处理策略:调度过于密集执行器来不及处理时的处理策略,策略包括:单机串行(默认)、丢弃后续调度、覆盖之前调度; 10、任务超时控制:支持自定义任务超时时间,任务运行超时将会主动中断任务; 11、任务失败重试:支持自定义任务失败重试次数,当任务失败时将会按照预设的失败重试次数主动进行重试;其中分片任务支持分片粒度的失败重试; 12、任务失败告警;默认提供邮件方式失败告警,同时预留扩展接口,可方便的扩展短信、钉钉等告警方式; 13、分片广播任务:执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发集群中所有执行器执行一次任务,可根据分片参数开发分片任务; 14、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。 15、事件触发:除了"Cron方式"和"任务依赖方式"触发任务执行之外,支持基于事件的触发任务方式。调度中心提供触发任务单次执行的API服务,可根据业务事件灵活触发。 16、任务进度监控:支持实时监控任务进度; 17、Rolling实时日志:支持在线查看调度结果,并且支持以Rolling方式实时查看执行器输出的完整的执行日志; 18、GLUE:提供Web IDE,支持在线开发任务逻辑代码,动态发布,实时编译生效,省略部署上线的过程。支持30个版本的历史版本回溯。 19、脚本任务:支持以GLUE模式开发和运行脚本任务,包括Shell、Python、NodeJS、PHP、PowerShell等类型脚本; 20、命令行任务:原生提供通用命令行任务Handler(Bean任务,"CommandJobHandler");业务方只需要提供命令行即可; 21、任务依赖:支持配置子任务依赖,当父任务执行结束且执行成功后将会主动触发一次子任务的执行, 多个子任务用逗号分隔; 22、一致性:“调度中心”通过DB锁保证集群分布式调度的一致性, 一次任务调度只会触发一次执行; 23、自定义任务参数:支持在线配置调度任务入参,即时生效; 24、调度线程池:调度系统多线程触发调度运行,确保调度精确执行,不被堵塞; 25、数据加密:调度中心和执行器之间的通讯进行数据加密,提升调度信息安全性; 26、邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件; 27、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用; 28、运行报表:支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等; 29、全异步任务调度流程全异步化设计实现,如异步调度、异步运行、异步回调等,有效对密集调度进行流量削峰,理论上支持任意时长任务的运行; 30、跨语言:调度中心与执行器提供语言无关的 RESTful API 服务,第三方任意语言可据此对接调度中心或者实现执行器。除此之外,还提供了 “多任务模式”和“httpJobHandler”等其他跨语言方案; 31、国际化:调度中心支持国际化设置,提供中文、英文两种可选语言,默认为中文; 32、容化:提供官方docker镜像,并实时更新推送dockerhub,进一步实现产品开箱即用; 33、线程池隔离:调度线程池进行隔离拆分,慢任务自动降级进入"Slow"线程池,避免耗尽调度线程,提高系统稳定性; 34、用户管理:支持在线管理系统用户,存在管理员、普通用户两种角色; 35、权限控

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值