解决Tomcat的shutdown.sh无法正常关闭tomcat的问题

这两天在给生产环境的服务器配置monit(一个Linux下非常实用轻型的监控工具),发觉monit不能通过界面正常的停止tomcat服务。究其原因是因为我的tomcat的服务脚本(/etc/init.d/tomcat1)里面停止tomcat是通过pkill命令强行杀掉的,脚本执行以后的返回结果是非零(好像137),而monit是通过判断返回值是否为零来决定脚本是否执行成功。没办法,只好将脚本改成通过tomcat自带的shutdown.sh来关闭服务了。这时候问题就出来了,由于应用程序里面集成了ehcache,Spring容器里面的cacheManager线程在ServletContext关闭的时候没有被destroy掉,导致tomcat服务停止的时候报以下错误,jvm进程没有退出:

SEVERE: The web application [/xyz] appears to have started a thread named [net.sf.ehcache.CacheManager@787db430] but has failed to stop it. This is very likely to create a memory leak.

这是由于在关闭Tomcat的时候,除了主线程以外尚有持续运行的线程没有退出。具体来讲就是每一个cacheManager对应的TerracottaClient会启动一个Runable的RejoinWorker,除非我们手动destroy这个cacheManager,不然这个worker线程不会正常退出。ehcache官方已经给出解决方案,就是在web.xml里面增加一个shutdownListener,在servletContext销毁之前自动关闭这个线程。具体写法如下:

<listener>
<listener-class>net.sf.ehcache.constructs.web.ShutdownListener</listener-class>
</listener>

在涉及到多线程编程的时候,新手通常喜欢通过while(true)来使线程循环做某件事,而又忘记了将线程设置成daemon模式。这是一个不好的编程习惯,这样的线程可控性很差,除非通过kill命令来杀掉jvm主进程,不然这些线程不会随着主线程的退出而退出。一旦应用里面有这样的线程存在,在通过shutdown.sh来关闭tomcat的时候会报类似下面这样的错误:
SEVERE: The web application [/*] appears to have started a thread named [Thread-4] but has failed to stop it. This is very likely to create a memory leak.

那么该如何避免这类情况的发生呢?答案是可以借助于JVM的shutdownHook来做手脚,让这些线程在创建之初就加入到Java Runtime的shutdownHook中,在JVM退出之前,shutdownHook里面的线程都会被一一的关掉。具体做法可以参考下面这篇文章:

Tomcat’s Graceful Shutdown with Daemons and Shutdown Hooks

发表评论?

0 条评论。

发表评论


注意 - 你可以用以下 HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>