Spring定時任務無故停止又不報錯的解決
Spring定時任務無故停止又不報錯
一開始是使用Spring自帶的定時器來配置定時任務的,簡單快捷,配置如下:
<bean id="refreshCache" class="com.gionee.baserom.search.job.RefreshCache" /> <task:scheduled-tasks> <task:scheduled ref="refreshCache" method="execute" cron="0 */30 * * * ?"/> </task:scheduled-tasks>
但是使用一段時間之後就無故停止,且不報錯,所以沒有相關錯誤日志,需要重啟Tomcat之後才能繼續執行定時任務。
開始以為由於數據庫最大連接數的限制,設置成翻倍瞭之後仍出現這問題。在同學的提醒下意識到可能是線程阻塞導致,於是網上查到原因:
Spring定時任務默認都是並發執行的,不會等待上一次任務執行完畢,隻要間隔時間到就會執行。
解決方案
1.將JobDetail的concurrent屬性配置為false。不允許任務並發執行。
2.任務執行時間較長時,查找根本問題。
於是把Spring自帶的定時器改用Quartz,依賴相關包:
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.1</version> </dependency>
定時任務配置如下:
<!-- 工作的bean --> <bean id="myJob" class=" com.gionee.baserom.exchangerate.job.DailyTaskJob" /> <!-- 定義任務,為瞭避免線程阻塞,用concurrent=false --> <bean id="myJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="myJob" /> <property name="targetMethod" value="execute" /> <property name="concurrent" value="false" /> </bean> <!-- 配置觸發器 --> <bean id="myJobTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="myJobDetail" /> <property name="cronExpression" value="0 0/30 * * * ?" /> </bean> <!-- 配置調度器 --> <bean name="startQuertz" lazy-init="false" autowire="no" destroy-method="destroy" class="com.gionee.baserom.exchangerate.util.SchedulerFactoryBeanWithShutdownDelay" > <property name="quartzProperties"> <props> <prop key="org.quartz.threadPool.threadCount">1</prop> </props> </property> <property name="waitForJobsToCompleteOnShutdown"> <value>false</value> </property> <property name="triggers"> <list> <ref bean="myJobTrigger" /> </list> </property> </bean>
在startQuartz中用到SchedulerFactoryBeanWithShutdownDelay是因為當Tomcat被關閉時,有可能導致任務線程並未完全關閉,導致內存泄漏。
SchedulerFactoryBeanWithShutdownDelay.java
import org.quartz.SchedulerException; import org.springframework.scheduling.quartz.SchedulerFactoryBean; public class SchedulerFactoryBeanWithShutdownDelay extends SchedulerFactoryBean { @Override public void destroy() throws SchedulerException { super.destroy(); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }
Spring定時任務跑完不再啟動
spring的定時任務有以下兩個特性
1、單定時任務之間是串行,之前的任務沒執行完,下一個任務不會啟動。
2、多個任務之間會相互幹擾,其他同一時刻啟動的任務沒執行完,下一個任務不會啟動。
排查方式
1、首先檢查自己的代碼,是否有死鎖、卡住、bug、http請求沒有設置超時時間等問題。
2、檢查是否所有定時任務都不啟動,如果是基本判斷是特性2導致的,檢查是哪個定時任務執行慢、卡住、出現bug等情況。
解決思路
1、修復bug,如果有的話。
2、如果就是有個任務執行慢,無法優化,可以不用spring的定時任務,改用Quartz。
依賴包
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.1</version> </dependency>
配置:
<!-- 工作的bean --> <bean id="myJob" class=" com.gionee.baserom.exchangerate.job.DailyTaskJob" /> <!-- 定義任務,為瞭避免線程阻塞,用concurrent=false --> <bean id="myJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="myJob" /> <property name="targetMethod" value="execute" /> <property name="concurrent" value="false" /> </bean> <!-- 配置觸發器 --> <bean id="myJobTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="myJobDetail" /> <property name="cronExpression" value="0 0/30 * * * ?" /> </bean> <!-- 配置調度器 --> <bean name="startQuertz" lazy-init="false" autowire="no" destroy-method="destroy" class="com.gionee.baserom.exchangerate.util.SchedulerFactoryBeanWithShutdownDelay" > <property name="quartzProperties"> <props> <prop key="org.quartz.threadPool.threadCount">1</prop> </props> </property> <property name="waitForJobsToCompleteOnShutdown"> <value>false</value> </property> <property name="triggers"> <list> <ref bean="myJobTrigger" /> </list> </property> </bean>
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 基於SSM 集成 Freemarker模板引擎的方法
- java的幾種定時器的具體使用(4種)
- Spring整合quartz做定時任務的示例代碼
- SpringBoot自動配置Quartz的實現步驟
- Spring概述和快速構建的方式