使用Quartz做计划任务时,默认情况下,当前任务总会执行,无论前一个任务是否结束。
使用Spring配置Quartz的Job的时候,也是默认当前任务总会执行,无论前一个任务是否结束。
因此,如果采用默认条件,需要考虑并发执行的逻辑问题,否则需要设置为顺序执行。
我写了一个Spring配置Quartz的Demo。里面Spring的xml中
代码如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:jms="http://www.springframework.org/schema/jms" xmlns:lang="http://www.springframework.org/schema/lang" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:oxm="http://www.springframework.org/schema/oxm" xmlns:p="http://www.springframework.org/schema/p" xmlns:sec="http://www.springframework.org/schema/security" xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-4.0.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-4.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"> <bean id="testJob" class="org.kanpiaoxue.learn.quartz.disallowConcurrentExecution.TestJob" /> <bean id="testJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="testJob" /> <property name="targetMethod" value="execute" /> <!-- 使用Quartz做计划任务时,默认情况下,当前任务总会执行,无论前一个任务是否结束。 设置 <property name="concurrent" value="false" /> 可以让Job顺序执行。 设置 <property name="concurrent" value="true" /> 可以让Job并行执行,而不用管上一个Job是否结束。 --> <property name="concurrent" value="false" /> </bean> <bean id="testJobCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="testJobDetail" /> <!-- 间隔1秒钟执行一次 --> <property name="cronExpression" value="0/1 * * * * ? *" /> </bean> <bean id="taskExecutor" class="org.kanpiaoxue.learn.quartz.disallowConcurrentExecution.ThreadPoolExecutorImpl"> <constructor-arg name="nThreads" value="30" /> </bean> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="taskExecutor" ref="taskExecutor" /> <property name="triggers"> <list> <ref bean="testJobCronTrigger" /> </list> </property> </bean> <!-- job end --> </beans>
Main函数的入口类如下:
import org.springframework.context.support.FileSystemXmlApplicationContext;
/**
* <pre>
* Test.java
* @author kanpiaoxue<br>
* @version 1.0
* Create Time 2014年8月12日 下午6:45:06<br>
* Description : main函数入口
* </pre>
*/
public class Test {
/**
* <pre>
* @param args
* </pre>
*/
@SuppressWarnings("resource")
public static void main(String[] args) {
new FileSystemXmlApplicationContext(
"D:/org/kanpiaoxue/learn/quartz/disallowConcurrentExecution/spring-ctx-application.xml");
}
}
Job的测试类如下:
import org.joda.time.DateTime;
import java.util.concurrent.TimeUnit;
/**
* <pre>
* TestJob.java
* @author kanpiaoxue<br>
* @version 1.0
* Create Time 2014年8月12日 下午6:45:48<br>
* Description : Job测试类
* </pre>
*/
public class TestJob {
public TestJob() {
}
public void execute() throws InterruptedException {
System.out.println(String.format("[%s] %s start to work", getNow(),
Thread.currentThread().getName()));
/**
* 让Job沉睡20秒,模拟当前Job一直在执行任务的情形。
*/
TimeUnit.SECONDS.sleep(20L);
System.out.println(String.format("[%s] %s wake up.", getNow(), Thread
.currentThread().getName()));
}
private String getNow() {
return DateTime.now().toString("yyyy-MM-dd HH:mm:ss");
}
}
如果不设置Spring的Quartz执行的线程大小,默认是:10个
我们也可以指定线程池的大小,代码如下:
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* <pre>
* ThreadPoolExecutorImpl.java
* @author kanpiaoxue<br>
* @version 1.0
* Create Time 2014年8月12日 下午7:04:44<br>
* Description : 线程池类
* </pre>
*/
public class ThreadPoolExecutorImpl extends ThreadPoolExecutor {
/**
* <pre>
* @param nThreads 线程池的大小
* </pre>
*/
public ThreadPoolExecutorImpl(int nThreads) {
super(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
}
通过在Spring的XML中配置 org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean 的 concurrent 的属性,可以决定Quartz的Job是否顺序执行,还是不考虑顺序的并行执行。
查看 MethodInvokingJobDetailFactoryBean 关于 concurrent 属性的原码,可以发现默认是“并行”的。
MethodInvokingJobDetailFactoryBean 的部分原码:
public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethodInvoker
implements FactoryBean<JobDetail>, BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean {
private static Class<?> jobDetailImplClass;
private static Method setResultMethod;
static {
try {
jobDetailImplClass = Class.forName("org.quartz.impl.JobDetailImpl");
}
catch (ClassNotFoundException ex) {
jobDetailImplClass = null;
}
try {
Class<?> jobExecutionContextClass =
QuartzJobBean.class.getClassLoader().loadClass("org.quartz.JobExecutionContext");
setResultMethod = jobExecutionContextClass.getMethod("setResult", Object.class);
}
catch (Exception ex) {
throw new IllegalStateException("Incompatible Quartz API: " + ex);
}
}
private String name;
private String group = Scheduler.DEFAULT_GROUP;
private boolean concurrent = true;
关于Quartz原生的Job的顺序执行,请参考文章: http://feuyeux.iteye.com/blog/1842966