2013-01-11 7 views
7

Sto utilizzando il framework Executors in Java per creare pool di thread per un'applicazione multithread e ho una domanda relativa alle prestazioni.Modo ottimale per creare un pool di thread di dimensioni fisse in Java utilizzando il servizio Executors

Ho un'applicazione che può funzionare in modalità in tempo reale o non in tempo reale. Nel caso in cui è in tempo reale, sto semplicemente usando la seguente:

THREAD_POOL = Executors.newCachedThreadPool(); 

Ma nel caso in cui non è in tempo reale, voglio la capacità di controllare le dimensioni del mio pool di thread. Per fare ciò, sto pensando a 2 opzioni, ma non capisco davvero la differenza e quale potrebbe funzionare meglio.

opzione 1 è quello di utilizzare il modo più semplice:

THREAD_POOL = Executors.newFixedThreadPool(threadPoolSize); 

opzione 2 è quello di creare il mio ThreadPoolExecutor in questo modo:

RejectedExecutionHandler rejectHandler = new RejectedExecutionHandler() { 
@Override 
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { 
    try { 
     executor.getQueue().put(r); 
    } catch (Exception e) {} 
} 
};   
THREAD_POOL = new ThreadPoolExecutor(threadPoolSize, threadPoolSize, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(10000), rejectHandler); 

vorrei capire qual è il vantaggio di utilizzare il opzione più complessa 2, e anche se dovrei usare un'altra struttura dati oltre a LinkedBlockingQueue? Qualsiasi aiuto sarebbe apprezzato.

risposta

13

Guardando il codice sorgente vi renderete conto che:

Executors.newFixedThreadPool(threadPoolSize); 

è equivalente a:

return new ThreadPoolExecutor(threadPoolSize, threadPoolSize, 0L, MILLISECONDS, 
           new LinkedBlockingQueue<Runnable>()); 

Dal momento che non prevede esplicitamente RejectedExecutionHandler, di default AbortPolicy viene utilizzato. Fondamentalmente genera RejectedExecutionException una volta che la coda è piena. Ma la coda è illimitata, quindi non sarà mai piena. Pertanto, questo esecutore accetta il numero di attività senza preavviso .

vostra dichiarazione è molto più complessa e piuttosto diverso:

  • new LinkedBlockingQueue<Runnable>(10000) farà sì che il pool di thread di scartare compiti se più di 10000 sono in attesa.

  • Non capisco cosa stia facendo il tuo RejectedExecutionHandler. Se il pool scopre che non può mettere altri runnables alla coda chiama il gestore. In questo gestore tu ... prova a mettere di nuovo lo Runnable nella coda (il che sarà fallito nel 99% dei casi del blocco). Alla fine tu inghiotti l'eccezione. Sembra che ThreadPoolExecutor.DiscardPolicy sia quello che cerchi.

    Guardando i commenti qui sotto sembra che stai cercando di bloccare o in qualche modo limitare i client se le attività in coda è troppo grande. Non credo che il blocco all'interno di RejectedExecutionHandler sia una buona idea. Considerare invece la politica di rifiuto CallerRunsPolicy. Non del tutto uguale, ma abbastanza vicino.

Per concludere: se si desidera limitare il numero di attività in sospeso, l'approccio è quasi buono. Se si desidera limitare il numero di thread simultanei, il primo one-liner è sufficiente.

1 - supponendo 2^31 è infinito

+0

Il 'RejectedExecutionHandler' è effettivamente bloccando, la chiamata a' executor.getQueue() mettere (r); 'bloccherà finché la coda libera, così. alla fine il mio gestore consente di mantenere una coda limitata senza interrompere alcun compito. A meno che non mi sbagli. +1 per gli altri dettagli. –

+0

@CharlesMenguy: grazie per i chiarimenti, il mio male, aggiornerò la mia domanda. Ma cosa vuoi ottenere bloccando "RejectedExecutionHandler"? Credo che potrebbe avere alcuni effetti collaterali davvero inaspettati come il blocco del thread del chiamante. Forse hai bisogno di 'CallerRunsPolicy'? –

+0

In realtà dopo averlo visto, 'CallerRunsPolicy' sembra davvero promettente per quello che voglio fare, ci provo grazie! Forse puoi aggiungerlo nella risposta e accetterò la tua risposta. –

Problemi correlati