Java 无法停止运行带有while(true)循环的web应用程序的tomcat服务器

Java 无法停止运行带有while(true)循环的web应用程序的tomcat服务器,java,tomcat,web-applications,Java,Tomcat,Web Applications,我正在开发一个部署到Tomcat上的web应用程序。启动Tomcat时,我使用servlet(在web.xml中)调用Java类: <web-app> <display-name>Consumer</display-name> <servlet> <servlet-name>start</servlet-name> <servlet-class>com.test.s

我正在开发一个部署到Tomcat上的web应用程序。启动Tomcat时,我使用servlet(在web.xml中)调用Java类:

<web-app>
    <display-name>Consumer</display-name>
    <servlet>
        <servlet-name>start</servlet-name>
        <servlet-class>com.test.sample.Consumer</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
</web-app>
有没有更好的方法来处理这个问题?还是发出停止信号以脱离环路

谢谢


更新为使用ServletContextListener:

public final class ApplicationListener implements ServletContextListener {

    private ScheduledExecutorService scheduler;

    public ApplicationListener() {
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        System.out.println("***** Stopping Consumer *****");
        scheduler.shutdownNow();
    }

    @Override
    public void contextInitialized(ServletContextEvent event) {

        System.out.println("***** Starting Consumer *****");

        scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(new ScheduledConsumer(), 0, 15000, TimeUnit.MILLISECONDS);

    }

    public class ScheduledConsumer implements Runnable {
        @Override
        public void run() {
            Consumer k = new Consumer();
            k.consumeOnce();
        }
    }
}

您必须将带有循环的代码放在不同的线程中,并从您的使用者处启动线程

private void consume() {
  Thread x = new Thread(new Runnable() {
    @Override
    public void run() {
      while(true) {
      ....
      }
   });
   x.start();
}

您必须将带有循环的代码放在不同的线程中,并从您的使用者处启动线程

private void consume() {
  Thread x = new Thread(new Runnable() {
    @Override
    public void run() {
      while(true) {
      ....
      }
   });
   x.start();
}

我有一些建议,但它们要求您稍微修改一下架构,以便更好地使用容器环境

Servlet容器支持可以获取各种事件通知的“侦听器”。具体地说,其中一个是
ServletContextListener
,它在上下文(又称webapp)投入使用时(通过
contextInitialized
方法)和退出服务时(通过
contextdestromed
方法)得到通知

我的建议是:

  • 更改
    使用者
    类的构造函数,使其不会自动调用
    使用者()
    ;相反,添加一个公共方法,如
    consumeOnce
    ,并且根本不在该级别使用循环
  • 编写一个
    ServletContextListener
    ,其中包含
    使用者
    线程
    引用以及
    可变布尔停止
    标志;在
    contextInitialized
    中,它应该创建一个新的
    Consumer
    对象,然后启动一个新的(守护进程)线程,该线程:
    • 呼叫消费者。消费一次
    • 调用
      Thread.sleep
      一段适当的时间
    • 循环前2个步骤,直到停止标志为真
  • 让您的
    ServletContextListener
    contextDestroyed
    方法将停止标志设置为
    true
    并调用
    线程。在运行的线程上中断

  • 我肯定我遗漏了一些确切的细节,但这是总的想法。当Tomcat关闭时,您的代码将收到关闭通知,您可以干净地终止自己的循环线程。您可能需要为
    使用者
    提供一种方法,使其在获得
    线程中断
    信号时,如果没有中止尝试使用它所使用的任何东西(例如,停止等待从空队列中提取对象),则可以中止尝试。(例如,如果您使用
    对象.wait()
    来等待监视器通知,那么您需要更改它,使其使用带超时的等待,这样您就不会永远阻塞)。

    我有一些建议,但它们要求您稍微修改一下体系结构,以便更好地使用容器环境

    Servlet容器支持可以获取各种事件通知的“侦听器”。具体地说,其中一个是
    ServletContextListener
    ,它在上下文(又称webapp)投入使用时(通过
    contextInitialized
    方法)和退出服务时(通过
    contextdestromed
    方法)得到通知

    我的建议是:

  • 更改
    使用者
    类的构造函数,使其不会自动调用
    使用者()
    ;相反,添加一个公共方法,如
    consumeOnce
    ,并且根本不在该级别使用循环
  • 编写一个
    ServletContextListener
    ,其中包含
    使用者
    线程
    引用以及
    可变布尔停止
    标志;在
    contextInitialized
    中,它应该创建一个新的
    Consumer
    对象,然后启动一个新的(守护进程)线程,该线程:
    • 呼叫消费者。消费一次
    • 调用
      Thread.sleep
      一段适当的时间
    • 循环前2个步骤,直到停止标志为真
  • 让您的
    ServletContextListener
    contextDestroyed
    方法将停止标志设置为
    true
    并调用
    线程。在运行的线程上中断

  • 我肯定我遗漏了一些确切的细节,但这是总的想法。当Tomcat关闭时,您的代码将收到关闭通知,您可以干净地终止自己的循环线程。您可能需要为
    使用者
    提供一种方法,使其在获得
    线程中断
    信号时,如果没有中止尝试使用它所使用的任何东西(例如,停止等待从空队列中提取对象),则可以中止尝试。(例如,如果您使用
    对象.wait()
    来等待监视器通知,那么您需要更改它,使其使用带超时的等待,这样您就不会永远阻塞)。

    谢谢,引入新线程会导致服务器启动时出现严重错误吗?错误很严重:加载应用程序时出现异常:java.lang.IllegalStateException:ContainerBase.addChild:start:org.apache.catalina.LifecycleException:org.apache.catalina.LifecycleException:java.lang.classcasteException:com.test.sample.Consumer无法强制转换为javax.servlet.servlet这根本没有帮助:线程将是一个非守护进程线程,不允许JVM关闭。即使将其转换为守护进程线程,也不会完全关闭。如果webapp被重新部署,而JVM没有重新启动,那么这将由于类装入器固定而导致PermGen(和一些常规堆)内存泄漏。在我的工作中,我使用MQ体系结构为同一个生产者/消费者案例执行此操作,并且我在启动或停止play服务器时没有遇到任何问题。我正在用netty运行它,但它也部署为在tomcat/jboss/中运行的war,如果这会产生问题,我会感到惊讶。停止