【问题标题】:ExecutorService in Java ServletJava Servlet 中的 ExecutorService
【发布时间】:2012-07-31 21:59:53
【问题描述】:

我需要在 java servlet 中同时执行一些任务(主要是使用请求参数调用多个外部 URL 并读取数据)并在几秒钟内向用户发送响应。我正在尝试使用 ExecutorService 来实现相同的目的。我需要在 doGet 方法的每个用户请求中创建四个 FutureTask。每个任务运行约 5-10 秒,对用户的总响应时间约为 15 秒。

您能否建议在 Java servlet 中使用 ExecutorService 时以下哪种设计更好?

1)(为每个请求创建 newFixedThreadPool 并尽快将其关闭)

public class MyTestServlet extends HttpServlet
{

    ExecutorService myThreadPool = null;

    public void init()
    {
          super.init();

    }
    protected void doGet(HttpServletRequest request,HttpServletResponse response)
    {

        myThreadPool = Executors.newFixedThreadPool(4);
        taskOne   = myThreadPool.submit();
        taskTwo   = myThreadPool.submit();        
        taskThree = myThreadPool.submit();
        taskFour  = myThreadPool.submit();

        ...
        ...

        taskOne.get();
        taskTwo.get();
        taskThree.get();
        taskFour.get();

        ...

        myThreadPool.shutdown();


    }

     public void destroy()
     {

         super.destroy();
     }

}

2)(在 Servlet Init 期间创建 newFixedThreadPool 并在 servlet 销毁时将其关闭)

public class MyTestServlet extends HttpServlet
{

    ExecutorService myThreadPool = null;

    public void init()
    {
      super.init();
          //What should be the value of fixed thread pool so that it can handle multiple   user requests without wait???
          myThreadPool = Executors.newFixedThreadPool(20);

    }
    protected void doGet(HttpServletRequest request,HttpServletResponse response)
    {


        taskOne   = myThreadPool.submit();
        taskTwo   = myThreadPool.submit();        
        taskThree = myThreadPool.submit();
        taskFour  = myThreadPool.submit();

        ...
        ...

        taskOne.get();
        taskTwo.get();
        taskThree.get();
        taskFour.get();

        ...



    }

     public void destroy()
     {

          super.destroy();
          myThreadPool.shutdown();
     }

}

3)(在 Servlet Init 期间创建 newCachedThreadPool 并在 servlet 销毁时将其关闭)

public class MyTestServlet extends HttpServlet
{

      ExecutorService myThreadPool = null;

      public void init()
      {
        super.init();
            myThreadPool = Executors.newCachedThreadPool();

      }
      protected void doGet(HttpServletRequest request,HttpServletResponse response)
      {


          taskOne   = myThreadPool.submit();
          taskTwo   = myThreadPool.submit();        
          taskThree = myThreadPool.submit();
          taskFour  = myThreadPool.submit();

          ...
          ...

          taskOne.get();
          taskTwo.get();
          taskThree.get();
          taskFour.get();

          ...




     }

     public void destroy()
     {

            super.destroy();
            myThreadPool.shutdown();
      }

}

【问题讨论】:

  • 容器创建并加载 servlet 的单个实例。并且所有请求都由同一个实例处理。所以,ExecutorService myThreadPool = null; 不安全。
  • 请问如何在全球范围内声明ExecutorService?

标签: java multithreading jakarta-ee servlets concurrency


【解决方案1】:

第一个不应该是一个选项。线程池(也可能是任何池)的想法是尽量减少构建池成员(在本例中为工作线程)所需的开销和内存。所以一般来说,池应该在你的应用程序启动时被初始化,并在它关闭时被销毁。

至于 2 和 3 之间的选择,请在下面的帖子中查看接受的答案。答案解释了差异,然后您可以决定哪一个更适合您的需求:newcachedthreadpool-v-s-newfixedthreadpool

【讨论】:

  • 感谢您的回答。根据您建议的链接,newcachedthreadpool 似乎很合适,因为我的任务与 http 请求相关联并在几秒钟内完成。
【解决方案2】:

为每个请求创建和销毁线程池是个坏主意:太贵了。

如果您有办法记住每个 URL 获取任务与哪个 HTTP 请求相关,我会选择 CachedThreadPool。它按需增长和收缩的能力会产生奇迹,因为 URL 获取任务是完全独立的并且受网络限制(与 CPU 或内存限制相反)。

另外,我会将 ThreadPool 包装在 CompletionService 中,它可以在作业完成时通知您,无论其提交顺序如何。先完成,先通知。如果更快的工作已经完成,这将确保您不会阻塞在一个缓慢的工作上。

CompletionService 易于使用:将其包装在现有的 ThreadPool 周围(例如 newCachedThreadPool),向其提交()作业,然后将结果返回()。请注意 take() 方法是阻塞的。

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CompletionService.html

【讨论】:

  • 感谢您的回答。您能否详细说明“如果您有办法记住每个 URL 获取任务与哪个 HTTP 请求相关”。如果我使用 cachedthreadpool ,任务和请求之间是否有可能不匹配?即使每个请求的线程池都相同,但每个请求的任务都是新的,一旦完成,我可以使用 .get() 方法检索它吗?
  • 嗯,我改变了主意 - 完成服务将要求您在 take() 方法上有一个线程块,然后将生成的 Future 重新调度到原始请求,这将非常复杂。您最好在标准 ExecutorService 上使用 invokeAll() :向它提交作业列表,它会返回结果列表。更简单、更高效。
猜你喜欢
  • 2016-05-07
  • 1970-01-01
  • 2014-11-15
  • 2010-09-29
  • 1970-01-01
  • 1970-01-01
  • 2011-12-11
  • 2016-12-19
  • 2015-02-15
相关资源
最近更新 更多