6

我需要在 java servlet 中同时执行一些任务(主要是使用请求参数调用多个外部 URL 并读取数据)并在几秒钟内向用户发送响应。我正在尝试使用 ExecutorService 来实现相同的目的。我需要在 doGet 方法的每个用户请求中创建四个 FutureTasks。每个任务运行约 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();
      }

}
4

2 回答 2

1

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

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

于 2012-08-02T21:56:24.080 回答
0

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

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

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

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

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

于 2012-08-02T22:47:22.660 回答