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..");
}
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级别,如果在应用程序中启动线程在应用程序关闭后并不会回收该线程。
相关文章
- 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端
- 对爱奇艺PC Web主站来说,良好的SEO能够帮助其获得更多的搜索流量,因而页面上一些非常重要的内容仍然需要依靠服务端进行渲染,由于另外开发一套基于Node的SSR后台成本较高,而乐趣(基于java和velocity模板引擎)平台作为渲染系统已经十分成熟且运行稳定,在充分试验后,我们决定在Uniqy中使用服务端同步与客户端浏览器异步二次渲染相结合的方式,结合Vue2.0提供的 slot插槽机制,很
- Springboot集成定时器和多线程异步处理操作
- 【JAVA】Quartz 任务调度和异步执行器
- 任务调度开源框架Quartz动态添加、修改和删除定时任务+调用与触发器表达式
- ROS机器人程序设计(原书第2版)补充资料 (肆) 第四章 在ROS下使用传感器和执行器
- 任务调度器和异步执行器