Tomcat servlet 应用程序的后台线程 [重复]

Posted

技术标签:

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

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

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

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

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

【问题讨论】:

值得注意的是,如果有比初始化上下文更方便的地方,通常可以在需要时启动线程。例如。它可能在特定 servlet 的 init 方法中,或者在特定类首次初始化时等。 【参考方案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)。

【讨论】:

以上是关于Tomcat servlet 应用程序的后台线程 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

27 | 新特性:Tomcat如何支持异步Servlet?

Servlet“已启动一个线程但未能停止它”-Tomcat 中的内存泄漏

Day694.Tomcat如何支持异步Servlet -深入拆解 Tomcat & Jetty

tomcat servlet 线程

Tomcat如何快速响应静态资源(DefaultServlet+浏览器缓存)

Tomcat如何快速响应静态资源(DefaultServlet+浏览器缓存)