Java 无法停止运行带有while(true)循环的web应用程序的tomcat服务器
我正在开发一个部署到Tomcat上的web应用程序。启动Tomcat时,我使用servlet(在web.xml中)调用Java类: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
<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,如果这会产生问题,我会感到惊讶。停止