Spring3.2.11与Quartz2.2.1整合时内存泄漏问题解决

2023-11-22 00:48

本文主要是介绍Spring3.2.11与Quartz2.2.1整合时内存泄漏问题解决,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Quartz是一款定时任务调度的开源框架,使用起来比较方便。并且Spring的support包对Quartz有集成。但是笔者在web应用使用的过程中却遇到了内存泄漏的问题。
问题的产生
笔者在使用Spring+Quartz的用法如下(熟悉Spring+Quartz的可以跳过直接看问题):
1.配置Scheduler工厂
<bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
</bean>
2.编写Job的实现类QuartzJob,用来执行任务
//这里须继承spring的QuartzJobBean
public class QuartzJob extends QuartzJobBean {/*** 任务执行内容。*/@Overrideprotected void executeInternal(JobExecutionContext context) throws JobExecutionException {// 执行任务的代码}
}

?
3.将Scheduler工厂生产的scheduler注入到业务逻辑类中。这里注意,注入的其实是由schedulerFactory生产出来的scheduler实例(对Spring不熟悉的人会自然而然的认为注入的是schedulerFactory的实例,这是因为Spring的SchedulerFactoryBean实现了FactoryBean接口,所以注入的结果会是FactoryBean.getObject()获得的实例,题外话)。
<bean id="taskService" class="com.xxxx.xx.service.impl.TaskServiceImpl" init-method="init" scope="singleton"><property name="scheduler"><ref bean="schedulerFactory"/></property></bean>public class TaskServiceImpl {private Scheduler scheduler;/*** 由spring通过工厂注入,此实例为单例。* @param scheduler*/public void setScheduler(Scheduler scheduler) {this.scheduler = scheduler;}

4.在业务逻辑类TaskServiceImpl中,使用scheduler执行任务。这里可以动态对任务执行增加、删除、重启等等操作。还有一个重要的特性是可以动态的改变Cron表达式,对任务的定时规则进行更改。
/*** 新增任务。* @param jobName* @param jobGroup* @param cron*/
public void addJob(String jobName, String jobGroup, String cron, String kindId) {try {if (StringUtil.isEmpty(jobName) || StringUtil.isEmpty(jobGroup) || StringUtil.isEmpty(cron)) {throw new BusinessException("定时任务创建失败,参数为空");}JobDetail jobDetail = JobBuilder.newJob(QuartzJob.class).withIdentity(jobName, jobGroup).build();jobDetail.getJobDataMap().put("JobKind", kindId);//表达式调度构建器CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);//按新的cronExpression表达式构建一个新的triggerCronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).withSchedule(scheduleBuilder).build();scheduler.scheduleJob(jobDetail, trigger);log.info("新增定时任务,name:" + jobName + ",group:" + jobGroup + ",cron:" + cron);} catch (SchedulerException e) {// 对异常的处理}
}

注意18行的scheduler是由Spring注入的。
这种用法在使用过程中没有问题,但在web应用在Tomcat6中热部署时出险了以下严重警告,如果忽略这种警告,在频繁的reload后会造成Tomcat 的 Permgen space OOM。
Jun 24, 2014 5:14:38 AM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/feeder##1.5.0] appears to have started a thread named [scheduler_Worker-1] but has failed to stop it. This is very likely to create a memory leak.
Jun 24, 2014 5:14:38 AM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/feeder##1.5.0] appears to have started a thread named [scheduler_Worker-2] but has failed to stop it. This is very likely to create a memory leak.
Jun 24, 2014 5:14:38 AM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/feeder##1.5.0] appears to have started a thread named [scheduler_Worker-3] but has failed to stop it. This is very likely to create a memory leak.
Jun 24, 2014 5:14:38 AM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/feeder##1.5.0] appears to have started a thread named [scheduler_Worker-4] but has failed to stop it. This is very likely to create a memory leak.
Jun 24, 2014 5:14:38 AM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/feeder##1.5.0] appears to have started a thread named [scheduler_Worker-5] but has failed to stop it. This is very likely to create a memory leak.
Jun 24, 2014 5:14:38 AM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/feeder##1.5.0] appears to have started a thread named [scheduler_Worker-6] but has failed to stop it. This is very likely to create a memory leak.
Jun 24, 2014 5:14:38 AM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads

问题的原因
究其原因是开启的scheduler_Worker线程没有关闭。但Spring的SchedulerFactoryBean实现了DisposableBean接口,表示web容器关闭时会执行destroy(),执行内容如下:
/*** Shut down the Quartz scheduler on bean factory shutdown,* stopping all scheduled jobs.*/public void destroy() throws SchedulerException {logger.info("Shutting down Quartz Scheduler");this.scheduler.shutdown(this.waitForJobsToCompleteOnShutdown);}


表示工厂已经做了shutdown。所以,问题出现在真正执行的scheduler.shutdown(true)。
原来这是Quartz的bug(见https://jira.terracotta.org/jira/browse/QTZ-192),在调用scheduler.shutdown(true)后,Quartz检查线程并没有等待那些worker线程被停止就结束了。
网上说在Quartz2.1版本已经修补了这个bug,但笔者使用的2.2.1版本仍旧有问题。
问题的解决
那么问题如何解决,这里有一个不太美观的方案:在调用scheduler.shutdown(true)后,增加一点睡眠时间,等待worker线程全部停止。如下:
1。自定义schedulerFactory继承Spring的SchedulerFactoryBean,覆盖destroy()增加延时。
public class SchedulerFactoryBeanWithShutdownDelay extends SchedulerFactoryBean {/*** 关于Quartz内存泄漏的不太美观的解决方案:* 在调用scheduler.shutdown(true)后增加延时,等待worker线程结束。*/@Overridepublic void destroy() throws SchedulerException {super.destroy();try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}

2。把spring配置文件中的SchedulerFactoryBean替换为自定义的工厂即可。
<bean id="schedulerFactory" class="com.sinosoft.ms.task.SchedulerFactoryBeanWithShutdownDelay">
</bean>
OK,问题解决。

这篇关于Spring3.2.11与Quartz2.2.1整合时内存泄漏问题解决的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/406262

相关文章

Spring三级缓存解决循环依赖的解析过程

《Spring三级缓存解决循环依赖的解析过程》:本文主要介绍Spring三级缓存解决循环依赖的解析过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、循环依赖场景二、三级缓存定义三、解决流程(以ServiceA和ServiceB为例)四、关键机制详解五、设计约

解决tomcat启动时报Junit相关错误java.lang.ClassNotFoundException: org.junit.Test问题

《解决tomcat启动时报Junit相关错误java.lang.ClassNotFoundException:org.junit.Test问题》:本文主要介绍解决tomcat启动时报Junit相... 目录tomcat启动时报Junit相关错误Java.lang.ClassNotFoundException

解决Maven项目报错:failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.13.0的问题

《解决Maven项目报错:failedtoexecutegoalorg.apache.maven.plugins:maven-compiler-plugin:3.13.0的问题》这篇文章主要介... 目录Maven项目报错:failed to execute goal org.apache.maven.pl

Android 12解决push framework.jar无法开机的方法小结

《Android12解决pushframework.jar无法开机的方法小结》:本文主要介绍在Android12中解决pushframework.jar无法开机的方法,包括编译指令、框架层和s... 目录1. android 编译指令1.1 framework层的编译指令1.2 替换framework.ja

MySQL主从同步延迟问题的全面解决方案

《MySQL主从同步延迟问题的全面解决方案》MySQL主从同步延迟是分布式数据库系统中的常见问题,会导致从库读取到过期数据,影响业务一致性,下面我将深入分析延迟原因并提供多层次的解决方案,需要的朋友可... 目录一、同步延迟原因深度分析1.1 主从复制原理回顾1.2 延迟产生的关键环节二、实时监控与诊断方案

SQLyog中DELIMITER执行存储过程时出现前置缩进问题的解决方法

《SQLyog中DELIMITER执行存储过程时出现前置缩进问题的解决方法》在SQLyog中执行存储过程时出现的前置缩进问题,实际上反映了SQLyog对SQL语句解析的一个特殊行为,本文给大家介绍了详... 目录问题根源正确写法示例永久解决方案为什么命令行不受影响?最佳实践建议问题根源SQLyog的语句分

Java NoClassDefFoundError运行时错误分析解决

《JavaNoClassDefFoundError运行时错误分析解决》在Java开发中,NoClassDefFoundError是一种常见的运行时错误,它通常表明Java虚拟机在尝试加载一个类时未能... 目录前言一、问题分析二、报错原因三、解决思路检查类路径配置检查依赖库检查类文件调试类加载器问题四、常见

解决IDEA报错:编码GBK的不可映射字符问题

《解决IDEA报错:编码GBK的不可映射字符问题》:本文主要介绍解决IDEA报错:编码GBK的不可映射字符问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录IDEA报错:编码GBK的不可映射字符终端软件问题描述原因分析解决方案方法1:将命令改为方法2:右下jav

MyBatis模糊查询报错:ParserException: not supported.pos 问题解决

《MyBatis模糊查询报错:ParserException:notsupported.pos问题解决》本文主要介绍了MyBatis模糊查询报错:ParserException:notsuppo... 目录问题描述问题根源错误SQL解析逻辑深层原因分析三种解决方案方案一:使用CONCAT函数(推荐)方案二:

Redis 热 key 和大 key 问题小结

《Redis热key和大key问题小结》:本文主要介绍Redis热key和大key问题小结,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录一、什么是 Redis 热 key?热 key(Hot Key)定义: 热 key 常见表现:热 key 的风险:二、