【问题标题】:Background Thread for a Tomcat servlet app [duplicate]Tomcat servlet 应用程序的后台线程 [重复]
【发布时间】:2010-10-21 23:25:36
【问题描述】:

我对 Tomcat 不是很熟悉,在我看来,它基本上被抽象为一个 cgi 服务器,可以在调用之间保存 JVM ——不过我知道它可以做的远不止这些。

我正在寻找一种在 Tomcat 服务器启动时启动 background 线程的方法,该线程会定期更新服务器上下文(在我的特定情况下,这是一个监听来自其他人的心跳的线程服务和更新可用性信息,但可以想象它的多种用途)。

有没有标准的方法来做到这一点?上下文的启动和更新/查询?

任何指向相关文档和/或代码示例的指针将不胜感激。

【问题讨论】:

  • 值得注意的是,如果有比初始化上下文更方便的地方,通常可以在需要时启动线程。例如。它可能在特定 servlet 的 init 方法中,或者在特定类首次初始化时等。

标签: java multithreading tomcat


【解决方案1】:

如果您使用基于 spring 的框架,您可以在 beans.xml 中指定要初始化的类/线程。所以当tomcat启动时,beans.xml会初始化里面提到的所有类。如果需要,您还可以传递构造函数参数。以下是相同的示例。

beans.xml

<bean id="monitoringSvc" class="com.mypackage.MonitoringService">
    <constructor-arg value="60"></constructor-arg>
</bean>

MonitoringService.java

public class MonitoringService{

     private MyThread myThread;

     public MonitoringService(int seconds){
          myThread = new MyThread(seconds);
          myThread.start();
     }
}    

【讨论】:

    【解决方案2】:

    如果你想在你的 WAR 部署时启动一个线程,你可以在 web.xml 中定义一个上下文监听器:

    <web-app>
        <listener>
           <listener-class>com.mypackage.MyServletContextListener</listener-class>
        </listener>
    </web-app>
    

    然后像这样实现那个类:

    public class MyServletContextListener implements ServletContextListener {
    
        private MyThreadClass myThread = null;
    
        public void contextInitialized(ServletContextEvent sce) {
            if ((myThread == null) || (!myThread.isAlive())) {
                myThread = new MyThreadClass();
                myThread.start();
            }
        }
    
        public void contextDestroyed(ServletContextEvent sce){
            try {
                myThread.doShutdown();
                myThread.interrupt();
            } catch (Exception ex) {
            }
        }
    }
    

    【讨论】:

    • 啊!谢谢,这很简单。我是否正确地说“ServletContext”是我需要修改以使该线程将信息传递给我的 servlet,以便它可以使用我的心跳侦听器收集的状态?
    • 是的,我的回答中错过了这一部分。 :) ServletConext 可从 ServletContextEvent 获得,它可以传递到您的 Thread 对象中,该对象可以获取/设置所有线程可用的属性。
    • 那个时候,怎么可能访问MyServletContextListener来查询线程呢?
    【解决方案3】:

    &lt;load-on-startup&gt;1&lt;/load-on-startup&gt; 放入web.xml 中的&lt;servlet&gt; 块将强制您的servlet 的init() 在Tomcat 启动后立即发生,而不是等待第一个请求到达。如果您想从 init() 生成后台线程,这很有用。

    【讨论】:

    • 这对我来说成功了,与这里的其他解决方案相比非常简单,但非常适合启动一些后台应用程序或守护程序。谢谢!
    【解决方案4】:

    我只是对 Chris 给出的非常详细的回答做一些小改动;我会将myThread 设置为myThread.setDaemon(true); 的守护线程,只要您有其他需要您的后台线程的非守护线程在工作,这基本上会保持线程处于活动状态。当所有这些线程完成时,您的守护程序线程将被 JVM 停止,您无需在contextDestroyed 中自行处理它。 但这只是我的 2 美分。

    【讨论】:

    • 除非你仍然需要在 contextDestroyed 中处理它。守护进程在最后一个非守护线程终止时终止,而不是在 servlet 上下文终止时终止。如果部署 WAR 文件来替换当前正在运行的文件,则旧 servlet 上下文中的守护线程将继续运行。这反过来又保留了该上下文的 ClassLoader,这是一个 PermGen 内存泄漏,这很糟糕。
    【解决方案5】:

    我正在寻找一种在 Tomcat 服务器启动时启动后台线程的方法

    我认为您正在寻找一种在 您的 Web 应用程序由 Tomcat 启动时启动后台线程的方法。

    这可以使用ServletContextListener 来完成。它在 web.xml 中注册,将在您的应用程序启动或停止时调用。然后,您可以使用普通的 Java 方法创建(或稍后停止)您的线程,以创建线程(或 ExecutionService)。

    【讨论】:

      猜你喜欢
      • 2012-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-09
      • 2012-09-17
      相关资源
      最近更新 更多