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

 更新时间:2021年11月02日 09:31:43   作者:思灵月  
这篇文章主要介绍了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>

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

相关文章

  • java 使用简单的demo实例告诉你优化算法的强大

    java 使用简单的demo实例告诉你优化算法的强大

    本篇文章介绍了,在java中使用简单的demo实例告诉你优化算法的强大。需要的朋友参考下
    2013-05-05
  • Java中的ThreadLocal详解

    Java中的ThreadLocal详解

    THreadLocalMap中的Entry的key使用的是ThreadLocal对象的弱引用,在没有其他地方对ThreadLoca依赖,ThreadLocalMap中的ThreadLocal对象就会被回收掉,但是对应的不会被回收,具体内容请和小编一起看下面文章详情
    2021-09-09
  • Java棋类游戏实践之中国象棋

    Java棋类游戏实践之中国象棋

    这篇文章主要为大家详细介绍了Java棋类游戏中的中国象棋实现方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-02-02
  • Hadoop源码分析四远程debug调试

    Hadoop源码分析四远程debug调试

    本篇是Hadoop源码分析系列文章第四篇,主要介绍一下Hadoop的远程debug调试步骤,后续本系列文章会持续更新,有需要的朋友可以借鉴参考下
    2021-09-09
  • mybatis-plus 拦截器敏感字段加解密的实现

    mybatis-plus 拦截器敏感字段加解密的实现

    数据库在保存数据时,对于某些敏感数据需要脱敏或者加密处理,本文主要介绍了mybatis-plus 拦截器敏感字段加解密的实现,感兴趣的可以了解一下
    2021-11-11
  • Spring AOP基本概念

    Spring AOP基本概念

    这篇文章主要为大家详细介绍了spring基础概念AOP与动态代理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能给你带来帮助
    2021-07-07
  • MybatisPlus更新时部分失败的问题解决

    MybatisPlus更新时部分失败的问题解决

    这篇文章主要为大家详细介绍了MybatisPlus更新时部分失败的问题分析和解决方法,文中的代码示例讲解的非常详细,需要的朋友可以参考下
    2023-06-06
  • Java深度优先遍历解决排列组合问题详解

    Java深度优先遍历解决排列组合问题详解

    这篇文章主要介绍了Java深度优先遍历解决排列组合问题详解,深度优先搜索是递归过程,带有回退操作,因此需要使用栈存储访问的路径信息,当访问到的当前顶点没有可以前进的邻接顶点时,需要进行出栈操作,将当前位置回退至出栈元素位置,需要的朋友可以参考下
    2024-01-01
  • Java开发中POJO和JSON互转时如何忽略隐藏字段的问题

    Java开发中POJO和JSON互转时如何忽略隐藏字段的问题

    这篇文章主要介绍了Java开发中POJO和JSON互转时如何忽略隐藏字段的问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02
  • Java字符串转驼峰格式的方法

    Java字符串转驼峰格式的方法

    在开发场景中,我们会遇到一些涉及字符串的转化,本文主要介绍了Java字符串转驼峰格式的方法,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01

最新评论