linux下tomcat shutdown后 java进程依旧存在


今天遇到一个很奇怪的问题,如标题所示:


linux下(之所以强调linux下,是因为在windows下正常),执行tomcat ./shutdown.sh 后,虽然tomcat服务不能正常访问了,但是ps -ef | grep java 后,发现tomcat对应的java进程未随web容器关闭而销毁,进而存在僵尸java进程。


刚开始百思不得其解,google下,发现存在一种说法是:有非守护线程(即User Thread)存在,jvm不会退出(当JVM中所有的线程都是守护线程的时候,JVM就可以退出了;如果还有一个或以上的非守护线程则JVM不会退出)。使用jstack工具进而确认是因为项目代码存在

scheduledExecutorService.scheduleAtFixedRate,众所周知,executorService会为之维护一个定时服务的线程池,该线程池并不会随着web容器关闭而销毁,不过有点让我很费解,尽管我已经在代码中addShutdownHook(shutdown()) ,但实际证明,这个hook只对Application.main时有效,在web容器中,hook会失效,所以并不会因为web容器关闭触发hook,进而能shutdownscheduledExecutorService。


关于此场景下hook在web容器失效猜测原因如下:

虚拟机jvm在执行关闭操作时,会先启动所有已经注册的关闭钩子,如果有的话,关闭钩子是先前已经通过RunTime类注册的线程,所有的关闭钩子会并发执行,直到完成任务。也就是shutdownhook执行的前提是jvm已经准备进行关闭操作,而正如前文所提到的此场景下由于非守护线程的存在,jvm并未能进行关闭操作,故shutdownhook也就无法触发执行。


PS:java虚拟机会对以下几种操作进行关闭:
(1) 系统调用System.exit()方法
(2) 程序最后一个守护线程退出时,应用程序正常退出。
(3) 用户强行中断程序运行,比如ctrl+c等其他方式中断java程序


(线程则是JVM级别的,如果你在Web 应用中启动一个线程,这个线程的生命周期并不会和Web应用程序保持同步。也就是说,即使你停止了Web应用,这个线程依旧是活跃的。正是因为这个很隐晦的问题,所以很多有经验的开发者不太赞成在Web应用中私自启动线程。

如果我们手工使用JDK Timer(Quartz的Scheduler),在Web容器启动时启动Timer,当Web容器关闭时,除非你手工关闭这个Timer,否则Timer中的任务还会继续运行!


Spring为JDK Timer和Quartz Scheduler所提供的TimerFactoryBean和SchedulerFactoryBean能够和Spring容器的生命周期关联,在 Spring容器启动时启动调度器,而在Spring容器关闭时,停止调度器。所以在Spring中通过这两个FactoryBean配置调度器,再从 Spring IoC中获取调度器引用进行任务调度将不会出现这种Web容器关闭而任务依然运行的问题。而如果你在程序中直接使用Timer或Scheduler,如不进行额外的处理,将会出现这一问题。


知道原因后,处理其实很简单,在ContextLoaderListener#contextDestroyed 容器关闭时主动销毁scheduledExecutorService:


    public void contextDestroyed(ServletContextEvent event)
    {
        //close ScheduledExecutorService in web container
        AccessTokenScheduled.shutdownScheduledExecutor();
        SystemTimer.shutdownScheduledExecutor();
        super.contextDestroyed(event);
        log.info("AppListener # context destroyed... ");
    }

如此,观察日志:

2014-08-13 09:47:33,977 INFO  [com.xx.util.AccessTokenScheduled] - AccessTokenScheduled shutdown hook run...
2014-08-13 09:47:33,977 INFO  [com.xx.util.AccessTokenScheduled] - try to shutdown ScheduledExecutor... 
2014-08-13 09:47:33,978 INFO  [com.xx.util.SystemTimer] - SystemTimer shutdown hook run...
2014-08-13 09:47:33,978 INFO  [com.xx.util.SystemTimer] - try to shutdown ScheduledExecutor... 

会发现证实了上述关于此场景下hook在web容器失效的原因的猜测是正确的,必须先确保jvm能正常退出,然后关闭钩子才会如期执行


参考:http://blog.sina.com.cn/s/blog_613904cc0101i5em.html

http://m.blog.csdn.net/blog/lin910429/25716113

http://www.2cto.com/kf/201305/214127.html



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值