"Tomcat+Spring+Quartz"解决方案下,关闭Tomcat出现"线程未关闭,出现内存泄漏"错误
2015-08-04 15:06
951 查看
使用"Tomcat+Spring+Quartz"解决方案,在关闭Tomcat时出现如图1所示错误信息:
图1
![](https://oscdn.geek-share.com/Uploads/Images/Content/202012/06/f5be3ded53bdd49f5bb839d3b1659350)
这里使用的Tomcat版本为6.2.32,Spring版本为3.2.3,Quartz版本为1.8.6
一、原因分析
在"Tomcat+Spring+Quartz"的解决方案中,Tomcat在运行的时候,Spring中配置的Quartz SchedulerFactoryBean会创建多个工作线程。在Tomcat关闭的时候,检测到这些线程没有得到及时的销毁,因而出现如图1的错误。
二、解决方案
Tomcat关闭的时候,会去销毁Spring实例。根据Spring的生命周期机制,在销毁Spring实例的过程中,会去处理Spring中配置的Bean实例的销毁事宜。只要Spring中配置的Bean实例符合以下图2中的任意一个条件
图2
![](https://oscdn.geek-share.com/Uploads/Images/Content/202012/06/0201193a2c1cdb9275aa92f50f824ffe)
Spring实例销毁过程中就会去调用这些Bean实例上的设置的销毁方法。
在我们的项目中,在Spring中配置Quartz SchedulerFactoryBean的片段如下:
因而网上很多“使调用SchedulerFactoryBean实例的销毁方法”的解决方案都是错误的,这些解决方案包括“在Spring中定义SchedulerFactoryBean实例时增加‘destroy-method’属性”,“实现一个监听器,使得在Tomcat销毁时去调用SchedulerFactoryBean实例的销毁方法”等。
实际上,产生以上错误的原因是在销毁过程中,SchedulerFactoryBean实例的destroy()方法的运行会给它创建的线程发送关闭指令,然后destroy()方法就运行完毕返回。但是其实这些线程真正关闭还是需要一定时间的,这产生了时延,因此当destroy()方法运行完毕返回,然后相应的Spring实例的销毁过程完成之后,Tomcat认为理应没有线程在运行,但是却发现还有线程在运行,因此就会抛出以上错误。
那么一种解决方案就是让SchedulerFactoryBean实例的destroy()方法等待一段时间再完成返回,相应的Spring实例的销毁过程也会等待该段时间,在这段时间内这些Quartz SchedulerFactoryBean的线程得以关闭,接着Tomcat检查的时候就不会抛出还有线程在运行出现内存泄漏的错误。
我创建了如下类:
三、其他
1、由于这些Quartz SchedulerFactoryBean创建的线程最后能够得以关闭,因此Tomcat进程也能被正常关闭,在有些情形中,Tomcat进程内的线程不能得以关闭,那么Tomcat进程也不能被正常关闭,只能通过kill命令,强行杀死进程。
2、这个问题已经在Quartz 2.1上修复
参考文献:
[1]http://forums.terracotta.org/forums/posts/list/3479.page
[2]http://stackoverflow.com/questions/2730354/spring-scheduler-shutdown-error
[3]https://jira.terracotta.org/jira/browse/QTZ-192
[4]http://forum.spring.io/forum/spring-projects/container/25869-quartz-doesn-t-shutdown
图1
这里使用的Tomcat版本为6.2.32,Spring版本为3.2.3,Quartz版本为1.8.6
一、原因分析
在"Tomcat+Spring+Quartz"的解决方案中,Tomcat在运行的时候,Spring中配置的Quartz SchedulerFactoryBean会创建多个工作线程。在Tomcat关闭的时候,检测到这些线程没有得到及时的销毁,因而出现如图1的错误。
二、解决方案
Tomcat关闭的时候,会去销毁Spring实例。根据Spring的生命周期机制,在销毁Spring实例的过程中,会去处理Spring中配置的Bean实例的销毁事宜。只要Spring中配置的Bean实例符合以下图2中的任意一个条件
图2
Spring实例销毁过程中就会去调用这些Bean实例上的设置的销毁方法。
在我们的项目中,在Spring中配置Quartz SchedulerFactoryBean的片段如下:
<bean id="startQuartz" lazy-init="false" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="doTime"/> </list> </property> </bean>查看org.springframework.scheduling.quartz.SchedulerFactoryBean的源代码,发现它继承org.springframework.beans.factory.DisposableBean接口,满足图2中的条件。因而在Spring实例的销毁过程中,SchedulerFactoryBean实例的destroy()方法会被自动调用。
因而网上很多“使调用SchedulerFactoryBean实例的销毁方法”的解决方案都是错误的,这些解决方案包括“在Spring中定义SchedulerFactoryBean实例时增加‘destroy-method’属性”,“实现一个监听器,使得在Tomcat销毁时去调用SchedulerFactoryBean实例的销毁方法”等。
实际上,产生以上错误的原因是在销毁过程中,SchedulerFactoryBean实例的destroy()方法的运行会给它创建的线程发送关闭指令,然后destroy()方法就运行完毕返回。但是其实这些线程真正关闭还是需要一定时间的,这产生了时延,因此当destroy()方法运行完毕返回,然后相应的Spring实例的销毁过程完成之后,Tomcat认为理应没有线程在运行,但是却发现还有线程在运行,因此就会抛出以上错误。
那么一种解决方案就是让SchedulerFactoryBean实例的destroy()方法等待一段时间再完成返回,相应的Spring实例的销毁过程也会等待该段时间,在这段时间内这些Quartz SchedulerFactoryBean的线程得以关闭,接着Tomcat检查的时候就不会抛出还有线程在运行出现内存泄漏的错误。
我创建了如下类:
package com.dslztx.utils; 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中的配置片段如下:
<bean id="startQuartz" lazy-init="false" autowire="no" class="com.dslztx.utils.SchedulerFactoryBeanWithShutdownDelay"> <property name="triggers"> <list> <ref bean="doTime"/> </list> </property> </bean>
三、其他
1、由于这些Quartz SchedulerFactoryBean创建的线程最后能够得以关闭,因此Tomcat进程也能被正常关闭,在有些情形中,Tomcat进程内的线程不能得以关闭,那么Tomcat进程也不能被正常关闭,只能通过kill命令,强行杀死进程。
2、这个问题已经在Quartz 2.1上修复
参考文献:
[1]http://forums.terracotta.org/forums/posts/list/3479.page
[2]http://stackoverflow.com/questions/2730354/spring-scheduler-shutdown-error
[3]https://jira.terracotta.org/jira/browse/QTZ-192
[4]http://forum.spring.io/forum/spring-projects/container/25869-quartz-doesn-t-shutdown
相关文章推荐
- Jetty和Tomcat的选择:按场景而定
- Jetty与tomcat的比较
- Jetty和tomcat的比较
- Tomcat的基本配置
- eclipse tomcat 目录
- JRE System Library [jdk1.7]和Server Library [Apache Tomcat v6.0]未绑定错误解决方案
- Tomcat介绍及性能优化
- JDK环境配置与Tomcat
- Nginx和tomcat同时配置ssl
- 在Windows的Tomcat环境下部署Solr 4.7.0
- tomcat solr 部署
- 手机游戏刷表流程记录—服务端菜鸟的成长之路
- tomcat 添加CROS跨源请求
- 在linux下面进行apache和tomcat的链接
- Apache Portable Runtime (APR) based Native library for Tomcat
- 改写tomcat重启脚本
- Jetty和tomcat的比较
- tomcat使用手册
- Tomcat服务器学习和使用(二)
- Tomcat服务器学习和使用(一)