0
点赞
收藏
分享

微信扫一扫

Spring使用之:Quartz定时任务为什么会被阻塞


问题:

周日,公司CTO给我打电话说,监控系统的数据从下午1点就不更新了。我登录服务器排除了数据同步问题,查看日志也没有例外抛出,查询了前一天的日志发现几个数据库表空间溢出例外。最后定位,Spring定时任务挂掉了。重启应用恢复正常。周一早上,同样的问题又发生了,6点开始定时任务又停了。Spring定时任务为什么会被阻塞呢?

原因:

周一中午,我在进行接口状态监控测试时发现,接口状态查询任务尽然会执行半小时。问题找到了,由于我在接口状态查询任务中没有设置读超时、在接口网络繁忙时,接口状态查询任务会占用很长的时间,Spring定时任务默认都是并发执行的,不会等待上一次任务执行完毕,只要间隔时间到就会执行。接口状态查询任务每5分钟执行一次,假如每次都执行1小时的话,其他任务就会被阻塞。因为Quartz的线程都被接口状态查询任务占用了。其他任务只有等待。

解决方法:

1.将JobDetail的concurrent属性配置为false。不允许任务并发执行。
2.任务执行时间较长时,查找根本问题。

实验:

JobOne.java
Java代码

package test.job; 


import java.util.Date; 


public class JobOne { 

 public void execute(){ 

 System.out.println("execute JobOne("+new Date()+")"); 

 try { 

 Thread.sleep(1000000); 

 }catch(InterruptedException ire) { 


 } 

 } 

} 


package test.job; 


import java.util.Date; 


public class JobOne { 

 public void execute(){ 

 System.out.println("execute JobOne("+new Date()+")"); 

 try { 

 Thread.sleep(1000000); 

 }catch(InterruptedException ire) { 


 } 

 } 

}


JobTwo.java
Java代码

package test.job; 


import java.util.Date; 


public class JobTwo { 

 public void execute(){ 

 System.out.println("execute JobTwo("+new Date()+")"); 

 } 


} 


package test.job; 


import java.util.Date; 


public class JobTwo { 

 public void execute(){ 

 System.out.println("execute JobTwo("+new Date()+")"); 

 } 


}



配置文件
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:tx="http://www.springframework.org/schema/tx" 

 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring- 


beans-2.0.xsd 

 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd 

 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"> 


 <!--===== jobOne =====--> 


 <!-- job --> 


 <bean id="jobOne" class="test.job.JobOne" > 


 </bean> 


 <!-- job detail --> 


 <bean id="jobOneDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> 

 <property name="targetObject" ref="jobOne"/> 

 <property name="targetMethod" value="execute"/> 

 <property name="concurrent" value="true" /> 

 </bean> 


 <!-- Trigger --> 


 <bean id="jobOneSimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> 

 <property name="jobDetail" ref="jobOneDetail" /> 

 <property name="startDelay"><value>0</value></property> 

 <property name="repeatInterval"><value>1000</value></property> 

 </bean> 


 <!--===== jobTwo =====--> 


 <!-- job --> 


 <bean id="jobTwo" class="test.job.JobTwo" > 


 </bean> 


 <!-- job detail --> 


 <bean id="jobTwoDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> 

 <property name="targetObject" ref="jobTwo"/> 

 <property name="targetMethod" value="execute"/> 

 <property name="concurrent" value="true" /> 

 </bean> 


 <!-- Trigger --> 


 <bean id="jobTwoSimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> 

 <property name="jobDetail" ref="jobTwoDetail" /> 

 <property name="startDelay"><value>0</value></property> 

 <property name="repeatInterval"><value>1000</value></property> 

 </bean> 



 <!--===== Schedule =====--> 


 <!-- schedule --> 


 <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> 

 <property name="triggers"> 

 <list> 

 <ref local="jobOneSimpleTrigger"/> 

 <ref local="jobTwoSimpleTrigger"/> 

 </list> 

 </property> 

 </bean> 


</beans> 


<?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:tx="http://www.springframework.org/schema/tx" 

 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd 

 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd 

 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"> 


 <!--===== jobOne =====--> 


 <!-- job --> 


 <bean id="jobOne" class="test.job.JobOne" > 


 </bean> 


 <!-- job detail --> 


 <bean id="jobOneDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> 

 <property name="targetObject" ref="jobOne"/> 

 <property name="targetMethod" value="execute"/> 

 <property name="concurrent" value="true" /> 

 </bean> 


 <!-- Trigger --> 


 <bean id="jobOneSimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> 

 <property name="jobDetail" ref="jobOneDetail" /> 

 <property name="startDelay"><value>0</value></property> 

 <property name="repeatInterval"><value>1000</value></property> 

 </bean> 


 <!--===== jobTwo =====--> 


 <!-- job --> 


 <bean id="jobTwo" class="test.job.JobTwo" > 


 </bean> 


 <!-- job detail --> 


 <bean id="jobTwoDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> 

 <property name="targetObject" ref="jobTwo"/> 

 <property name="targetMethod" value="execute"/> 

 <property name="concurrent" value="true" /> 

 </bean> 


 <!-- Trigger --> 


 <bean id="jobTwoSimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> 

 <property name="jobDetail" ref="jobTwoDetail" /> 

 <property name="startDelay"><value>0</value></property> 

 <property name="repeatInterval"><value>1000</value></property> 

 </bean> 



 <!--===== Schedule =====--> 


 <!-- schedule --> 


 <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> 

 <property name="triggers"> 

 <list> 

 <ref local="jobOneSimpleTrigger"/> 

 <ref local="jobTwoSimpleTrigger"/> 

 </list> 

 </property> 

 </bean> 


</beans>



MAIN类:
Java代码

package test.job; 


import org.springframework.context.ApplicationContext; 

import org.springframework.context.support.ClassPathXmlApplicationContext; 


public class JobTest { 

 private ApplicationContext ac; 


 public JobTest(ApplicationContext ac) { 

 this.ac = ac; 

 } 

 /** 

 * @param args 

 */ 

 public static void main(String[] args) { 

 JobTest job = new JobTest(new ClassPathXmlApplicationContext("applicationContext.xml")); 



 } 


} 


package test.job; 


import org.springframework.context.ApplicationContext; 

import org.springframework.context.support.ClassPathXmlApplicationContext; 


public class JobTest { 

 private ApplicationContext ac; 


 public JobTest(ApplicationContext ac) { 

 this.ac = ac; 

 } 

 /** 

 * @param args 

 */ 

 public static void main(String[] args) { 

 JobTest job = new JobTest(new ClassPathXmlApplicationContext("applicationContext.xml")); 



 } 


}



测试结果:

当jobOne的concurrent为true时:

execute JobOne(Thu Jan 24 13:40:22 CST 2008)
execute JobTwo(Thu Jan 24 13:40:22 CST 2008)
execute JobOne(Thu Jan 24 13:40:22 CST 2008)
execute JobTwo(Thu Jan 24 13:40:22 CST 2008)
execute JobOne(Thu Jan 24 13:40:23 CST 2008)
execute JobTwo(Thu Jan 24 13:40:23 CST 2008)
execute JobOne(Thu Jan 24 13:40:24 CST 2008)
execute JobTwo(Thu Jan 24 13:40:24 CST 2008)
execute JobOne(Thu Jan 24 13:40:25 CST 2008)
execute JobTwo(Thu Jan 24 13:40:25 CST 2008)
execute JobOne(Thu Jan 24 13:40:26 CST 2008)
execute JobTwo(Thu Jan 24 13:40:26 CST 2008)
execute JobOne(Thu Jan 24 13:40:27 CST 2008)
execute JobTwo(Thu Jan 24 13:40:27 CST 2008)
execute JobOne(Thu Jan 24 13:40:28 CST 2008)
execute JobTwo(Thu Jan 24 13:40:28 CST 2008)
execute JobOne(Thu Jan 24 13:40:29 CST 2008)
execute JobTwo(Thu Jan 24 13:40:29 CST 2008)
execute JobOne(Thu Jan 24 13:40:31 CST 2008)

(JobOne并发执行,到这里所有任务阻塞没有信息输出,可以看出默认有10个线程,都被JobOne占用)

当jobOne的concurrent为false时:

execute JobOne(Thu Jan 24 13:43:00 CST 2008)
execute JobTwo(Thu Jan 24 13:43:00 CST 2008)
execute JobTwo(Thu Jan 24 13:43:00 CST 2008)
execute JobTwo(Thu Jan 24 13:43:01 CST 2008)
execute JobTwo(Thu Jan 24 13:43:02 CST 2008)
execute JobTwo(Thu Jan 24 13:43:03 CST 2008)
execute JobTwo(Thu Jan 24 13:43:04 CST 2008)
execute JobTwo(Thu Jan 24 13:43:05 CST 2008)
execute JobTwo(Thu Jan 24 13:43:06 CST 2008)
execute JobTwo(Thu Jan 24 13:43:07 CST 2008)
execute JobTwo(Thu Jan 24 13:43:08 CST 2008)
execute JobTwo(Thu Jan 24 13:43:09 CST 2008)

(JobOne不并发执行,JobTwo不会被阻塞)


4 楼 雁行 2008-01-25 引用
我们jobdetail用的是org.springframework.scheduling.quartz.JobDetailBean
可以设置超时时间
不过从某种意义上来说,不如并发设置为false好些。

3 楼 wangrui 2008-01-24 引用
任务的时间超不超过定时器的间隔,我觉得编程时无法决定,或者说你认为它不会,实际什么情况都会发生。我这个系统运行了半年了也没出现问题。可是还是出了这样的问题。设计时还是应该好好考虑,如果任务不需要并发就将concurrent设为false比较保险。
2 楼 jones 2008-01-24 引用
implements StatefulJob使Job成为有状态的,顺序执行
1 楼 agile_boy 2008-01-24 引用
执行任务的时间不应该超过定时器的间隔吧,否则就会发生阻塞。

举报

相关推荐

0 条评论