这是我之前的问题的后续跟进.
Tomcat 5.0.28有一个错误,即关闭时容器没有调用Servlet的destroy()方法.这在Tomcat 5.0.30中得到修复,但如果Servlet的destroy()方法有一个System.exit(),则会导致Tomcat windows服务抛出错误1053并拒绝正常关闭(有关详细信息,请参阅上面的链接)这个错误)
任何人都知道是否:
在Servlet的destroy()方法中调用System.exit()强制终止任何非守护进程线程是一个好主意?
如果Servlet的destroy()方法中存在System.exit(),为什么Tomcat 5.0.30和(包括Tomcat 6.xx的更高版本)无法正常关闭.
matt b.. 16
在Servlet的destroy()方法中调用System.exit()强制终止任何非守护进程线程是一个好主意?
这绝对不是一个好主意 - 这是一个可怕的想法.destroy()
当servlet停止服务时调用该方法,这可能由于多种原因而发生:servlet/webapp已停止,webapp正在取消部署,webapp正在重新启动等.
System.exit()
关闭整个JVM!为什么要简单地因为卸载一个servlet而强行关闭整个服务器?
如果Servlet的destroy()方法中存在System.exit(),为什么Tomcat 5.0.30和(包括Tomcat 6.xx的更高版本)无法正常关闭.
可能是为了防止这样的危险行为.
您不应该编写代码,假定您的代码/应用程序是服务器上运行的唯一内容.
在Servlet的destroy()方法中调用System.exit()强制终止任何非守护进程线程是一个好主意?
这绝对不是一个好主意 - 这是一个可怕的想法.destroy()
当servlet停止服务时调用该方法,这可能由于多种原因而发生:servlet/webapp已停止,webapp正在取消部署,webapp正在重新启动等.
System.exit()
关闭整个JVM!为什么要简单地因为卸载一个servlet而强行关闭整个服务器?
如果Servlet的destroy()方法中存在System.exit(),为什么Tomcat 5.0.30和(包括Tomcat 6.xx的更高版本)无法正常关闭.
可能是为了防止这样的危险行为.
您不应该编写代码,假定您的代码/应用程序是服务器上运行的唯一内容.
你问了两个问题:
问题1:在Servlet的destroy()方法中调用System.exit()强制杀死任何非守护进程线程是个好主意吗?
在任何与servlet相关的方法中调用System.exit()总是100%不正确.您的代码不是JVM中运行的唯一代码 - 即使您是唯一运行的servlet(servlet容器具有在JVM真正退出时需要清理的资源.)
处理这种情况的正确方法是在destroy()方法中清理线程.这意味着以允许您以正确方式轻轻地停止它们的方式启动它们.这是一个例子(MyThread是你的一个线程,并扩展了ServletManagedThread):
public class MyServlet extends HttpServlet { private Listthreads = new ArrayList (); // lots of irrelevant stuff left out for brevity public void init() { ServletManagedThread t = new MyThread(); threads.add(t); t.start(); } public void destroy() { for(ServletManagedThread thread : threads) { thread.stopExecuting(); } } } public abstract class ServletManagedThread extends Thread { private boolean keepGoing = true; protected abstract void doSomeStuff(); protected abstract void probablySleepForABit(); protected abstract void cleanup(); public void stopExecuting() { keepRunning = false; } public void run() { while(keepGoing) { doSomeStuff(); probablySleepForABit(); } this.cleanup(); } }
还有值得注意的是,有一些线程/并发库可以帮助解决这个问题 - 但如果你真的有一些在servlet初始化时启动并且应该运行直到servlet被销毁的线程,这可能就是你需要的全部内容.
问题2:如果Servlet的destroy()方法中存在System.exit(),为什么Tomcat 5.0.30和(包括Tomcat 6.xx的更高版本)无法正常关闭?
没有更多的分析,很难确定. 微软表示,当Windows要求服务关闭时,会出现错误1053,但请求超时.这将使Tomcat内部发生的事情变得非常糟糕.我当然会怀疑你的电话System.exit(
可能是罪魁祸首.Tomcat(特别是Catalina)确实在VM上注册了一个关闭钩子(see org.apache.catalina.startup.Catalina.start()
至少在5.0.30中).当你调用时,JVM会调用那个关闭钩子System.exit()
.关闭挂钩委托给正在运行的服务,因此可能需要每个服务执行大量工作.
如果关闭hooks(triggered by your System.exit()
)无法执行(它们死锁或类似的东西),那么很容易理解错误1053发生的原因,给定Runtime.exit(int)
方法的文档(从中调用System.exit()
):
如果在虚拟机开始其关闭序列后调用此方法,则如果正在运行关闭挂钩,则此方法将无限期地阻塞.如果已经运行了关闭挂钩并且已启用了退出终结,则此方法如果状态为非零,则使用给定的状态代码暂停虚拟机; 否则,它会无限期地阻止.
这种"无限期阻塞"行为肯定会导致错误1053.
如果您想要比此更完整的答案,您可以下载源代码并自行调试.
但是,我愿意打赌,如果你正确处理线程管理问题(如上所述),你的问题就会消失.
简而言之,将System.exit()调用留给Tomcat - 这不是你的工作.