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 {/**
* 任务执行内容。
*/
@Override
protected 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表达式构建一个新的trigger
CronTrigger 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线程结束。
*/
@Override
public 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整合时内存泄漏的问题的解决的更多相关文章
- Spring整合quartz关闭,关闭Tomcat Servlet容器时内存泄漏
出错信息 22-Sep-2017 06:19:51.064 WARNING [main] org.apache.catalina.loader.WebappClassLoaderBase.clearR ...
- Spring3 + Spring MVC+ Mybatis 3+Mysql 项目整合(注解及源码)
Spring3 + Spring MVC+ Mybatis 3+Mysql 项目整合(注解及源码) 备注: 之前在Spring3 + Spring MVC+ Mybatis 3+Mysql 项目整合中 ...
- Spring+Mybatis整合时 Failed to read candidate component class,Caused by:IllegalArgumentException
Spring+Mybatis整合时Caused by: java.lang.IllegalArgumentException错误 org.springframework.beans.factory.B ...
- Spring与Struts2整合时action自动注入的问题
当Struts和Spring框架进行整合时,原本由action实例化对象的过程移交给spring来做(这个过程依赖一个叫struts2-spring-plugin的jar包,这个包主要的功能就是实现刚 ...
- C++11 shared_ptr 智能指针 的使用,避免内存泄露
多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...
- 用ssh整合时,用sessionfactory的getCurrentSession()获取不到session
在用ssh整合时,一开始用的是getCurrentSession(),获取当前线程上的session,但是总是抛异常,不能获取. 后来用sessionfactory的openSession(),但是, ...
- 三大框架SSH(struts2+spring+hibernate)整合时相关配置文件的模板
最近在学SSH三大框架的整合,在此对他们整合时相关配置文件做一简单的模板总结,方便以后复用! 首先是web.xml配置文件,这里面就配置一些简单的监听器.过滤器,包括spring核心配置文件appli ...
- 在Oracle 11.2的数据库中建表时遇到 RESULT_CACHE (MODE DEFAULT) ORA-00922: missing or invalid option
在Oracle 11.2的数据库中建表时遇到 RESULT_CACHE (MODE DEFAULT) ORA-00922: missing or invalid option hostdr:[/ho ...
- 关于Struts与Ajax整合时的异常处理
关于Struts与Ajax整合时的异常处理问题: 问题还原: 从而当有异常发出时,会将异常信息发送到页面上.如下图所示:这是一个比较经典的过程: 错误提示页面: 由于sendError()方法里 ...
随机推荐
- FastGUI for NGUI教程
原地址:http://blog.csdn.net/asd237241291/article/details/8499430 FastGUI是NGUI的一个扩展,所以必须要有NGUI才能使用.FastG ...
- Django——Django,uwsgi Nginx组合建站
近来抽时间看了点关于python的资料,试着架设了下运行环境,于是写了本文记录之. 用到的软件: Django-1.6.1 uwsgi-2.0.7 python-3.3.3 nginx-1.7.7 安 ...
- 【Python3 爬虫】05_安装Scrapy
Scrapy简介 Scrapy是用纯Python实现一个为了爬取网站数据.提取结构性数据而编写的应用框架,用途非常广泛.框架的力量,用户只需要定制开发几个模块就可以轻松的实现一个爬虫,用来抓取网页内容 ...
- mongoDB 数据导出之mongoexport的用法
http://tuozixuan.iteye.com/blog/1321994 实战代码: #mongo导出 mongoexport --port 33001 -d bsdf_soe -c ...
- WPF开源框架项目
好久博客未更新新博文了,今天介绍一个WPF开源框架MaterialDesignInXamlToolkit废话不多说先让我们来看看框架得几张截图 让我们一起来看看源代码得结构如下图 接下我们运行代码看看 ...
- 递归函数, 匿名函数, yield from
递归函数 函数执行流程 http://pythontutor.com/visualize.html#mode=edit 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1 ...
- Failed to load http://localhost:8080/team.php: Request header field x-jwt-header is not allowed by Access-Control-Allow-Headers in preflight response.
axios 加入header之后,请求出现 Failed to load http://localhost:8080/team.php: Request header field x-jwt-head ...
- Event 带参
var handler={ message:"Event handled.", handlerFun:function(){ alert(this.message) } }; // ...
- JavaScript之字符串、对象及操作符
字符串-String 字符串就是字符序列. 字符串中,有些特殊字符,叫做字面量,常见的字面量如下表: 判断字符串长度使用length属性 text.length; 字符串拼接 var a = 'Jav ...
- 教你实现类似于格瓦拉启动页中的放大转场动画(OC&Swift)
教你实现类似于格瓦拉启动页中的放大转场动画(OC&Swift) 一.前言 用过格瓦拉电影,或者其他app可能都知道,一种点击按钮用放大效果实现转场的动画现在很流行,效果大致如下 在iOS中,在 ...