欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring定时任务无故停止又不报错的解决

程序员文章站 2022-09-10 10:19:18
目录spring定时任务无故停止又不报错解决方案spring定时任务跑完不再启动spring的定时任务有以下两个特性排查方式解决思路spring定时任务无故停止又不报错一开始是使用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>

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。