2012-08-02 22 views
5

Ho bisogno di eseguire alcune attività (principalmente chiamata più URL esterni con parametri di richiesta e dati di lettura) contemporaneamente nel servlet Java e inviare risposta all'utente entro pochi secondi. Sto cercando di utilizzare ExecutorService per ottenere lo stesso . Ho bisogno di quattro FutureTask creati in ogni richiesta utente nel metodo doGet. Ogni attività viene eseguita per circa 5-10 secondi e il tempo di risposta totale per l'utente è di circa 15 secondi.ExecutorService in Java Servlet

Potete suggerire quale dei seguenti progetti è migliore durante l'uso di ExecutorService in un servlet Java?

1) (Creazione di newFixedThreadPool per richiesta e chiuderlo 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) (Creazione di newFixedThreadPool durante Servlet Init e chiuderlo sul servlet distruggere)

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) (Creazione di newCachedThreadPool durante Servlet Init e spegnimento su 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

Il contenitore crea e carica una singola istanza del servlet. E tutte le richieste vengono elaborate dalla stessa istanza. Quindi, 'ExecutorService myThreadPool = null;' non è sicuro. –

+0

Quindi, per favore, può suggerire come dichiarare ExecutorService a livello globale? – user1263019

risposta

1

Il primo non dovrebbe essere un'opzione. L'idea di un pool di thread (e probabilmente qualsiasi pool) è di minimizzare il sovraccarico e la memoria necessari per la costruzione dei membri del pool (in questo caso, i thread worker). quindi In generale, i pool devono essere inseriti quando l'applicazione viene avviata e distrutta quando si spegne.

Per quanto riguarda la scelta tra 2 e 3, si prega di controllare la risposta accettata nel seguente post. La risposta spiega la differenza e si può quindi decidere quale si adatta alle vostre esigenze meglio: newcachedthreadpool-v-s-newfixedthreadpool

+0

Grazie per la risposta. Basandosi sul link che hai suggerito newcachedthreadpool sembra adatto in quanto le mie attività sono legate a una richiesta http e complete in pochi secondi. – user1263019

0

creare e distruggere un pool di thread per ogni richiesta è una cattiva idea: troppo costoso.

Se si dispone di un modo per ricordare quale richiesta HTTP è associata a ciascuna attività di recupero degli URL, sceglierei CachedThreadPool. La sua capacità di crescere e rimpicciolirsi su richiesta farà miracoli, perché le attività di recupero dell'URL sono totalmente indipendenti e legate alla rete (al contrario della CPU o legate alla memoria).

Inoltre, vorrei avvolgere ThreadPool in un CompletionService, che può avvisarti ogni volta che un lavoro viene eseguito, indipendentemente dal suo ordine di invio. Prima completata, prima notificata. Ciò garantirà che non si blocchi su un lavoro sloooow se quelli più veloci sono già stati eseguiti.

CompletionService è facile da utilizzare: avvolgere un ThreadPool esistente (newCachedThreadPool ad esempio), inoltrare() processi ad esso e quindi riprendere() i risultati. Si noti che il metodo take() sta bloccando.

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

+0

Grazie per la risposta. Puoi per favore elaborare "Se hai un modo per ricordare quale richiesta HTTP ogni attività di recupero dell'URL è correlata a". C'è qualche possibilità di mis-match tra task e request se utilizzo cachedthreadpool?Anche se threadpool è lo stesso per ogni richiesta, l'attività sarà nuova per ogni richiesta e posso recuperare utilizzando il metodo .get() una volta completato correttamente? – user1263019

+1

Hummm Ho cambiato idea: un servizio di completamento richiede di avere un blocco di thread sul metodo take() e quindi di ridispacciare il futuro risultante alla richiesta di origine, il che sarebbe piuttosto complicato. Faresti meglio a utilizzare invokeAll() su un ExecutorService standard: invia un elenco di lavori e ti restituisce un elenco di risultati. Più facile e più efficiente. –