Spring中Quartz的Job顺序执行

使用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

猜你喜欢

转载自kanpiaoxue.iteye.com/blog/2103210