当前位置: 首页 > 面试题库 >

在Servlet的destroy()方法中调用System.exit()

郭兴平
2023-03-14
问题内容

这是我先前提出的问题的后续措施。

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的更高版本)无法正确关闭。


问题答案:

您在问两个问题:

问题1:在Servlet的destroy()方法中调用System.exit()以强行杀死任何非守护进程线程是一个好主意吗?

在任何与Servlet相关的方法中调用System.exit()总是100%错误。您的代码不是在JVM中运行的唯一代码- 即使您是唯一在运行
的servlet(该servlet容器具有在JVM真正退出时也需要清除的资源)。

处理这种情况的正确方法是在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();
    }
}

还值得注意的是,那里有线程/并发库可以帮助您解决问题-
但是,如果您确实有少数几个线程是在Servlet初始化时启动的,并且应该一直运行到Servlet被销毁,这可能就是您所需要的。

问题2:如果Servlet的destroy()方法中存在System.exit(),为什么Tomcat 5.0.30及更高版本(包括Tomcat
6.xx的更高版本)无法正确关闭?

没有更多的分析,很难确定。 Microsoft说
Windows要求关闭服务但请求超时时,会发生错误1053。那将使它看起来像是在Tomcat内部发生了某种事情,使它陷入了非常糟糕的状态。我当然怀疑您致电System.exit()可能是罪魁祸首。Tomcat(特别是Catalina)确实在VM中注册了一个关闭钩子(see org.apache.catalina.startup.Catalina.start(),至少在5.0.30中)。调用时,JVM将调用该关闭挂钩System.exit()。关闭挂钩代表正在运行的服务,因此可能需要每个服务执行大量工作。

如果关闭钩子(triggered by your System.exit())无法执行(它们死锁或类似的问题),则在给出该Runtime.exit(int)方法的文档(从中调用System.exit())的情况下,很容易理解为什么会发生错误1053

如果在虚拟机开始其关闭序列后调用此方法,则如果正在运行关闭挂钩,则此方法将无限期阻塞。如果已经运行了关闭挂钩,并且启用了退出完成功能,则如果状态为非零,则此方法将使用给定的状态代码来暂停虚拟机;否则,此方法将暂停虚拟机。否则,它将无限期地阻塞。

此“不确定阻止”行为肯定会导致错误1053。

如果您想要比此更完整的答案,则可以下载源代码并自行调试。

但是,我愿意打赌,如果您正确地处理了线程管理问题(如上所述),您的问题将会消失。

简而言之,将System.exit()调用留给Tomcat-这不是您的工作。



 类似资料:
  • init和destroy方法分别在Servlet容器建立Servlet对象和销毁Servlet对象时调用。而且这两个方法只在Servlet的生命周期里调用一次。在Servlet接口中定义了这两个方法,在GenericServlet类中提供了这两个方法的默认实现。init方法有一个ServletConfig类型的参数,可以通过这个参数获得配置信息(也就是在web.xml文件中配置的内容),关于Ser

  • 我试图在点击事件上使用ajax调用servlet。从那个servlet,我称之为谷歌身份验证endpoint。我尝试将标头设置为我正在调用的servlet,但我无法摆脱此错误 XMLHttpRequest 无法加载 https://accounts.google.com/o/oauth2/auth?client_id=2536-a...nid 个人资料电子邮件 这是代码 在servlet上,我将其

  • 问题内容: 在下面的示例中,我无法弄清楚为什么未触发$ destroy事件。有人可以解释为什么不触发它,以及在什么情况下会触发它吗? 这是pl客:http ://plnkr.co/edit/3Fz50aNeuculWKJ22iAX?p=preview JS HTML 问题答案: 问题是您正在上监听事件,但正在上触发该事件。 来自angular.js来源(我确定它已记录在网站上的某个地方,但我没有看

  • Fire-and-forget 的调用方法极其简单。正如您从 快速开始 一节中了解到,您只需要传递一个具有相应方法和参数的lambda表达式: BackgroundJob.Enqueue(() => Console.WriteLine("Hello, world!")); Enqueue 方法不会立即调用目标方法,而是运行以下步骤: 序列化目标方法及其所有参数。 根据序列化的信息创建一个新的后台任

  • 问题内容: 我正在尝试调用我编写的方法。它只编译一行… 我不是最好的Java专家,但我认为像这样调用该方法将得到响应。不显示“ Hello”,但是… 如何正确调用该方法? 问题答案: 编辑:毫无疑问,这个答案仅解决了为什么您遇到编译时错误。它 没有 解决您在Android中的哪个线程以及什么时间应该做什么。 我个人建议您暂时放下Android,在更简单的环境(例如控制台应用程序)中学习Java,然