使用while(true)循环停止运行Web应用程序的tomcat服务器时遇到问题 [英] Trouble stopping a tomcat server that is running a web application with a while (true) loop

查看:359
本文介绍了使用while(true)循环停止运行Web应用程序的tomcat服务器时遇到问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm developing a web application to be deployed onto Tomcat. When Tomcat is started, I use a servlet (in web.xml) to call a Java class:

<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>

我的Consumer.java订阅了AMQP服务器上的队列。我通过使用 while(true)循环来实现这一点,这在独立的Java程序中运行良好。它也适用于Web应用程序的上下文,但我永远不能停止我的Tomcat服务器(在我的NetBeans IDE中),我相信while循环是罪魁祸首。以下是一些代码:

My Consumer.java subscribes to a queue on an AMQP server. I achieve this by using a while (true) loop, which works fine in a standalone Java program. Itt also works in the context of the web application, but I can never stop my Tomcat server (within my NetBeans IDE), and I believe that the while loop is the culprit. Here is some code:

public class Consumer {
    public Consumer()
        consume();
    }

    private void consume()

        ...

        while (true) {
            // Await incoming messages from queue
            // Process message
        }

    }

}

有没有更好的方法来处理这个问题?或者发出停止信号以阻止循环?

Is there a better way to handle this? Or to signal a stop to break out of the loop?

谢谢!

更新为使用ServletContextListener:

Updated to use 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();
        }
    }
}


推荐答案

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

I have some suggestions, but they require that you modify your architecture a bit in order to more nicely play with your container environment.

Servlet容器支持监听器 这可以获得各种事件的通知。具体来说,其中一个是 ServletContextListener ,当上下文(也称为webapp)投入使用时(通过 contextInitialized 方法)以及何时停止服务(通过 contextDestroyed 方法)。

Servlet containers support "listeners" that can get notification of various events. Specifically, one of them is the ServletContextListener which gets notified when the context (aka. webapp) is being brought into service (via the contextInitialized method) and when it is being brought out of service (via the contextDestroyed method).

我的建议是执行以下操作:

My recommendation would be to do the following:


  1. 更改消费者类的构造函数,以便它不会自动调用 consume();相反,添加一个公共方法,如 consumeOnce ,并且不要在该级别使用循环

  2. 写一个 ServletContextListener 具有 Consumer Thread 引用作为成员以及 volatile boolean stop flag;在 contextInitialized 中它应该创建一个新的 Consumer 对象,然后启动一个新的(守护进程)线程:

    • 致电 Consumer.consumeOnce

    • 致电 Thread.sleep 适当的时间

    • 循环前两步直到停止标志为真

  1. Change your Consumer class's constructor so that it does not automatically call consume(); instead, add a public method like consumeOnce and don't use a loop at that level at all
  2. Write a ServletContextListener that has a Consumer and a Thread reference as members as well as a volatile boolean stop flag; in contextInitialized it should create a new Consumer object, then launch a new (daemon) thread that:
    • Calls Consumer.consumeOnce
    • Calls Thread.sleep for an appropriate amount of time
    • Loops over the previous 2 steps until the stop flag is true

我确定我错过了一些确切的细节,但这是一般的想法。当Tomcat关闭时,您的代码将收到关闭通知,您可以干净地终止自己的循环线程。您可能需要为 Consumer 提供一种方法来中止尝试消耗它消耗的任何内容(例如,如果它没有,则停止等待从空队列中提取对象)当它获得 Thread.interrupt 信号时中止。 (例如,如果您使用 Object.wait()以等待监视器通知,那么您将要更改它,以便它使用等待超时所以你不会永远阻止。)

I'm sure I'm missing some exact details, but that's the general idea. When Tomcat shuts down, your code will be notified of the shutdown and you can cleanly terminate your own looping-thread. You may need to provide a way for the Consumer to abort an attempt to consume whatever it consumes (e.g. stop waiting to pull an object from an empty queue) if it doesn't abort when it gets a Thread.interrupt signal. (For instance if you use an Object.wait() in order to wait for a monitor notification, then you'll want to change that so it uses a wait with a timeout so that you won't block forever).

这篇关于使用while(true)循环停止运行Web应用程序的tomcat服务器时遇到问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆