java 在 Servlet 的 destroy() 方法中调用 System.exit()
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/546097/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Calling System.exit() in Servlet's destroy() method
提问by Nikhil Kashyap
This is a follow up to my earlier question.
这是对我之前问题的跟进。
Tomcat 5.0.28 had a bug where the Servlet's destroy() method was not being invoked by the container on a shutdown. This is fixed in Tomcat 5.0.30, but if the Servlet's destroy() method had a System.exit(), it would result in the Tomcat windows service throwing the Error 1053 and refusing to shutdown gracefully (see above link for more details on this error)
Tomcat 5.0.28 有一个错误,即在关闭时容器未调用 Servlet 的 destroy() 方法。这在 Tomcat 5.0.30 中已修复,但如果 Servlet 的 destroy() 方法有一个 System.exit(),则会导致 Tomcat windows 服务抛出错误 1053 并拒绝正常关闭(有关更多详细信息,请参阅上面的链接这个错误)
Anybody has any idea on whether:
任何人都知道是否:
Calling System.exit() inside a Servlet's destroy() method to forcefully kill any non-daemon threads is a good idea?
Why does Tomcat 5.0.30 and (later versions including Tomcat 6.x.x) fail to shutdown properly if there's a System.exit() in the destroy() method of the Servlet.
在 Servlet 的 destroy() 方法中调用 System.exit() 以强行杀死任何非守护进程线程是个好主意吗?
如果 Servlet 的 destroy() 方法中有 System.exit(),为什么 Tomcat 5.0.30 和(包括 Tomcat 6.xx 的更高版本)无法正常关闭。
回答by matt b
Calling System.exit() inside a Servlet's destroy() method to forcefully kill any non-daemon threads is a good idea?
在 Servlet 的 destroy() 方法中调用 System.exit() 以强行杀死任何非守护进程线程是个好主意吗?
It is absolutely not a good idea - it is a horrible idea. The destroy()method is called when the servlet is taken out of service, which can happen for any number of reasons: the servlet/webapp has been stopped, the webapp is being undeployed, the webapp is being restarted etc.
这绝对不是一个好主意——这是一个可怕的主意。destroy()当 servlet 停止服务时调用该方法,这可能由于多种原因而发生:servlet/webapp 已停止、webapp 正在取消部署、webapp 正在重新启动等。
System.exit()shuts down the entire JVM! Why would you want to forcibly shutdown the entire server simply because one servlet is being unloaded?
System.exit()关闭整个JVM!为什么仅仅因为正在卸载一个 servlet 就想强行关闭整个服务器?
Why does Tomcat 5.0.30 and (later versions including Tomcat 6.x.x) fail to shutdown properly if there's a System.exit() in the destroy() method of the Servlet.
如果 Servlet 的 destroy() 方法中有 System.exit(),为什么 Tomcat 5.0.30 和(包括 Tomcat 6.xx 的更高版本)无法正常关闭。
Probably to prevent such dangerous behavior like this.
可能是为了防止这种危险的行为。
You shouldn't write code that assumes that your code/application is the only thing running on the server.
您不应该编写假定您的代码/应用程序是服务器上唯一运行的代码。
回答by Jared
You're asking two questions:
你问两个问题:
Question 1: Is calling System.exit() inside a Servlet's destroy() method to forcefully kill any non-daemon threads a good idea?
问题 1:在 Servlet 的 destroy() 方法中调用 System.exit() 来强行杀死任何非守护进程线程是个好主意吗?
Calling System.exit() inside ANY servlet-related method is always 100% incorrect. Your code is not the only code running in the JVM - even if you are the only servlet running(the servlet container has resources it will need to cleanup when the JVM really exits.)
在任何与 servlet 相关的方法中调用 System.exit() 总是 100% 不正确。您的代码不是在 JVM 中运行的唯一代码 -即使您是唯一运行的 servlet(servlet 容器具有在 JVM 真正退出时需要清理的资源。)
The correct way to handle this case is to clean up your threads in the destroy() method. This means starting them in a way that lets you gently stop them in a correct way. Here is an example (where MyThread is one of your threads, and extends ServletManagedThread):
处理这种情况的正确方法是在 destroy() 方法中清理线程。这意味着以一种让您以正确的方式轻轻地停止它们的方式启动它们。这是一个示例(其中 MyThread 是您的线程之一,并且扩展了 ServletManagedThread):
public class MyServlet extends HttpServlet {
private List<ServletManagedThread> threads = new ArrayList<ServletManagedThread>();
// 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();
}
}
It's also worth noting that there are thread/concurrency libraries out there that can help with this - but if you really do have a handful of threads that are started at servlet initialization and should run until the servlet is destroyed, this is probably all you need.
还值得注意的是,有一些线程/并发库可以帮助解决这个问题——但如果你真的有一些线程在 servlet 初始化时启动并且应该运行直到 servlet 被销毁,这可能就是你所需要的.
Question 2: Why does Tomcat 5.0.30 and (later versions including Tomcat 6.x.x) fail to shutdown properly if there's a System.exit() in the destroy() method of the Servlet?
问题2:为什么Tomcat 5.0.30 和(包括Tomcat 6.xx 在内的更高版本)在Servlet 的destroy() 方法中有System.exit() 时无法正常关闭?
Without more analysis, it's hard to know for certain. Microsoft saysthat Error 1053 occurs when Windows asks a service to shutdown, but the request times out. That would make it seem like something happened internally to Tomcat that got it into a really bad state. I would certainly suspect that your call to System.exit() could be the culprit. Tomcat (specifically, Catalina) does register a shutdown hook with the VM (see org.apache.catalina.startup.Catalina.start(), at least in 5.0.30). That shutdown hook would get called by the JVM when you call System.exit(). The shutdown hook delegates to the running services, so each service could potentially be required to do alot of work.
没有更多的分析,很难确定。 微软表示,当 Windows 要求服务关闭但请求超时时,会发生错误 1053。这会让人觉得 Tomcat 内部发生了一些事情,导致它进入了一个非常糟糕的状态。我当然怀疑您对System.exit()的调用可能是罪魁祸首。Tomcat(特别是 Catalina)确实向 VM 注册了关闭挂钩(see org.apache.catalina.startup.Catalina.start()至少在 5.0.30 中)。当您调用System.exit(). 关闭钩子委托给正在运行的服务,因此每个服务都可能需要做很多工作。
If the shutdown hooks (triggered by your System.exit()) fail to execute (they deadlock or something like that,) then it is very easy to understand why the Error 1053 occurs, given the documentation of the Runtime.exit(int)method (which is called from System.exit()):
如果关闭挂钩 ( triggered by your System.exit()) 无法执行(它们死锁或类似的情况),那么很容易理解错误 1053 发生的原因,鉴于Runtime.exit(int)方法的文档(从 调用System.exit()):
If this method is invoked after the virtual machine has begun its shutdown sequence then if shutdown hooks are being run this method will block indefinitely. If shutdown hooks have already been run and on-exit finalization has been enabled then this method halts the virtual machine with the given status code if the status is nonzero; otherwise, it blocks indefinitely.
如果在虚拟机开始其关闭序列后调用此方法,则如果正在运行关闭挂钩,则此方法将无限期阻塞。如果关闭钩子已经运行并且退出完成已经启用,那么如果状态非零,则此方法将停止具有给定状态代码的虚拟机;否则,它会无限期地阻塞。
This "indefinite blocking" behavior would definitely cause an Error 1053.
这种“无限期阻塞”行为肯定会导致错误 1053。
If you want a more complete answer than this, you can download the sourceand debug it yourself.
如果您想要比这更完整的答案,您可以下载源代码并自行调试。
But, I would be willing to bet that if you properly handle your thread management issue (as outlined above,) your problems will go away.
但是,我敢打赌,如果您正确处理线程管理问题(如上所述),您的问题就会消失。
In short, leave the System.exit() call to Tomcat - that's not your job.
简而言之,将 System.exit() 调用留给 Tomcat - 这不是您的工作。
回答by James Schek
Calling System.exit() inside a Servlet's destroy() method to forcefully kill any non-daemon threads is a good idea?
在 Servlet 的 destroy() 方法中调用 System.exit() 以强行杀死任何非守护进程线程是个好主意吗?
Not a good idea. You will forcefully kill allthreads, which might include part of Tomcat that is currently shutting down the system. This will cause Tomcat to un-gracefully shutdown. This can also prevent shutdown handlers from running which can lead to all sorts of problems.
不是个好主意。您将强制终止所有线程,其中可能包括当前正在关闭系统的 Tomcat 的一部分。这将导致 Tomcat 异常关闭。这也可以防止关闭处理程序运行,这可能导致各种问题。
Why does Tomcat 5.0.30 and (later versions including Tomcat 6.x.x) fail to shutdown properly if there's a System.exit() in the destroy() method of the Servlet.
如果 Servlet 的 destroy() 方法中有 System.exit(),为什么 Tomcat 5.0.30 和(包括 Tomcat 6.xx 的更高版本)无法正常关闭。
A lotof code executes after a Servlet destory. The Context destroy and all of its other listeners for one... other servlets. Other applications. Tomcat itelf. By calling System.exit, you prevent all of that from running.
一个很多的代码一个Servlet destory之后执行。Context 会销毁一个...其他 servlet 的所有其他侦听器。其他应用。Tomcat 本身。通过调用 System.exit,您可以阻止所有这些运行。
A better question is what are thse non-daemon threads, why are they running, and who starts them?
一个更好的问题是这些非守护线程是什么,它们为什么运行,以及谁启动它们?
回答by James Schek
When writing thread shutdown code like Jared's, I normally make the "keepGoing" member and "stopExecuting()" method static so that all threads get the signal to go down with one shutdown call. Good idea or no?
在编写像 Jared 那样的线程关闭代码时,我通常将“keepGoing”成员和“stopExecuting()”方法设为静态,以便所有线程通过一次关闭调用获得关闭的信号。好主意与否?

