在servlet容器中启动线程池

时间:2008-12-26 01:48:13

标签: multithreading tomcat servlets

我有一个servlet S来处理来自第三方站点的回调。

回调调用按特定顺序发生。因此,我需要排队。

我建议使用像

这样的内存中队列
java.util.ConcurrentLinkedQueue

所以逻辑看起来像这样:

  • Servlet S接收回调&将收到的项目排队到队列Q中。
  • 此时,托管servlet S实例的线程将终止。
  • 消费者线程从Q读取并按顺序处理每个线程。

据我所知,Servlet S的每个实例都在自己的Thread中执行。

如何为将为Queue提供服务的整个webapp(war)创建单个Consumer Thread?基本上我需要单例实例:

  1. 线程池
  2. 的ConcurrentLinkedQueue

5 个答案:

答案 0 :(得分:5)

这不是servlet容器的用途。如果您打算使用基于标准的方法,那么您真的需要一个更加完善的J2EE应用程序服务器。你将拥有的是其他黑客,但它们可能足以完成你的任务。

我可能会尝试创建一个DaemonServlet。这只是一个没有映射到URL的普通servlet(可能是用于监视目的的盲目URL,尽管更喜欢JMX用于此类事情)。加载servlet时会调用init()方法。你可以在那里开始一个线程。可以说你可能需要创建两个:一个完成工作。另一个确保第一个正在运行,并在调用destroy()后正常终止它。

或者,如果您正在使用Spring(并且,让我们面对它,什么样的whacko不使用Spring?),您可以简单地在应用程序上下文中创建一个大致相同的bean事情,除了Spring生命周期事件(例如InitializingBean上的afterPropertiesSet())。

实际上,我有一个更好的建议。使用asynchronous message consumers,这将更清晰,更具可扩展性,但这取决于基于JMS的解决方案,而不仅仅是LinkedBlockingQueue(而且JMS可能是一个更好的主意) 。根据您的约束,您可能没有选择JMS作为选项。

答案 1 :(得分:2)

请记住,虽然您的servlet位于单独的线程中,但它们位于同一个VM实例中,因此它们位于共享内存空间中。如果您创建一个Singleton实例,它将自动由所有servlet共享。您还可以创建一个单独的servlet作为共享数据,这样做的好处是,如果需要,可以使用容器服务来保留它。

在OReilly关于servlet编程的书中,有一种彻底的检查方法 - 技术上称为“servlet协作” - 可在线获取here

答案 2 :(得分:1)

哦,另一个想法:你不想做的一件事是尝试在servlet容器内管理你自己的线程池;它可以比你更好地进行线程池化,除非你弄乱它。

答案 3 :(得分:0)

我认为管理自己的线程池是一个坏主意。

Servlet用于处理HTTP请求。 HTTP是同步请求/响应协议。他们如何处理的逻辑属于其他地方。该处理程序可以是同步的或异步的,但应该由处理程序实现决定。 servlet应该决定为给定的响应推迟哪个处理程序,就是这样。

即使您使用Tomcat或servlet / JSP引擎,您仍然可以通过将ActiveMQ添加到Tomcat实现来使用Spring,JMS和MDP。

答案 4 :(得分:0)

使用侦听器,我创建了一个ThreadPool,可以使用ServletContext与旧版Tomcat应用程序集成,以存储ThreadPool并让侦听器管理生命周期,以免延误。

@WebListener
public class MyThreadPool implements ServletContextListener {

    private static final String CONTEXT_ATTRIBUTE = "MyThreadPool";
    private ExecutorService myThreadPool;

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        myThreadPool = Executors.newFixedThreadPool(10);
        sce.getServletContext().setAttribute(CONTEXT_ATTRIBUTE, myThreadPool);
    }

    public static ExecutorService getPool(Servlet servlet) {
        return (ExecutorService) servlet.getServletConfig()
               .getServletContext().getAttribute(CONTEXT_ATTRIBUTE);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        myThreadPool.shutdown();
        sce.getServletContext().removeAttribute(CONTEXT_ATTRIBUTE);
    }
}