Java Servlet中的ExecutorService

我需要在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 destroy上关闭它)

 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 destroy上关闭它)

 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(); } } 

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

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

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

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

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

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

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