2012-08-02 39 views
5

我需要執行一些任務(主要進行調用多個外部URL與請求參數和讀取數據),同時在Java servlet和幾個seconds.I內發送響應用戶想使用的ExecutorService來達到同樣的。我需要在doGet方法中的每個用戶請求中創建四個FutureTasks。每個任務運行約5-10秒,對用戶的總響應時間約爲15秒。的ExecutorService中的Java Servlet

可否請您提出以下哪些設計是更好的,而在一個Java servlet使用的ExecutorService?

1)(創建每個請求的newFixedThreadPool和關閉它ASAP)

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初始化期間創建的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初始化期間創建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(); 
     } 

} 
+0

容器創建並加載servlet的單個實例。所有請求都由同一個實例處理。所以,'ExecutorService myThreadPool = null;'是不安全的。 – 2012-08-02 21:54:01

+0

那麼可以請建議如何在全局聲明ExecutorService?我的任務是綁在HTTP請求和幾秒鐘內完成 – user1263019 2012-08-03 00:00:19

回答

1

第一個不應該是一個選項。一個線程池(也可能是任何池)的想法是,以儘量減少對池成員的建設所需的開銷和內存(在這種情況下,工作線程)。所以一般情況下,應用程序在啓動時應該被啓動並在關閉時被銷燬。

至於2和3之間的選擇,請在下面的帖子接受的答案。答案解釋的差異,那麼你就可以決定哪一個適合您的需求更好地:newcachedthreadpool-v-s-newfixedthreadpool

+0

感謝answer.Based的鏈接,你曾建議newcachedthreadpool似乎適合。 – user1263019 2012-08-03 00:02:42

0

創建和銷燬每個請求的線程池是一個壞主意:太貴了。

如果你有某種方式來記住哪些HTTP請求每個URL抓取任務涉及到,我會去一個CachedThreadPool。它的增長和收縮點播會創造奇蹟,因爲URL抓取任務是完全獨立的和網絡結合的(而不是CPU或者內存限制的)能力。

另外,我想包在CompletionService,每當作業完成後,不管其提交訂單的,可以通知你的線程池。首先完成,首先通知。這樣可以確保你不會因爲速度更快的工作而阻止工作。

CompletionService易於使用:它環繞現有的線程池(newCachedThreadPool例如),提交()作業,然後採取()的返回結果。請注意,take()方法被阻塞。

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

+0

感謝您的回答。你可以請詳細說明:「如果你有一些方法來記住哪些HTTP請求每個URL抓取任務是有關」。如果我使用cachedthreadpool,任務和請求之間是否有任何不匹配的機會?即使每個請求的線程池都相同,每個請求的任務都是新的,並且一旦它完成正確,我可以使用.get()方法進行檢索? – user1263019 2012-08-03 00:08:03

+1

Hummm我改變了主意 - 完成服務將要求您在take()方法上有一個線程塊,然後重新分配產生的Future到原始請求,這將非常複雜。你最好在標準的ExecutorService上使用invokeAll():提交一份工作列表,並且給你一個結果列表。更簡單,更高效。 – 2012-08-03 08:47:14