2009-12-21 9 views
7

Sto avendo questo problema, hoJava: SingleThreadScheduledExecutor & java.util.concurrent.RejectedExecutionException

private ScheduledExecutorService executor = 
    Executors.newSingleThreadScheduledExecutor(); 

e il compito che viene creato ogni 50 millliseconds:

executor.scheduleAtFixedRate(myTask, 0, 50, TimeUnit.MILLISECONDS); 

myTask a volte prendere un po ' per completare (come 2-3 secondi o giù di lì), ma newSingleThreadScheduledExecutor garantisce che il prossimo myTask pianificato attenderà fino al completamento di quello corrente.

Tuttavia, ottengo questo errore di tanto in tanto:

eseguire: java.util.concurrent.RejectedExecutionException

Cosa devo fare? Grazie

+0

prega di essere più preciso su ciò che yyou dire con "di tanto in tanto". Questa eccezione dovrebbe essere lanciata solo al momento di chiamare 'execute()' su ExecutorService. –

+0

In realtà, RejectedExecutionException è lanciabile da executor.scheduleAtFixedRate() –

+0

@Andrey, è necessario fornirci molte più informazioni, iniziando da una traccia dello stack che mostra l'eccezione. –

risposta

11

Considerate ciò che l'esecutore sta facendo. Esegue una singola attività ogni 50 millisecondi, secondo le tue istruzioni. Supponendo che questa attività richieda meno di 50 millisecondi per essere eseguita, allora tutto va bene. Tuttavia, ogni tanto ci vogliono 2-3 secondi per funzionare. Quando ciò accade, l'executor tenta ancora di eseguire ogni 50 millisecondi, ma poiché ha solo un singolo thread, non può, e rifiuta quelle esecuzioni che vengono attivate mentre l'attività a lungo termine è ancora in corso. Ciò causa l'eccezione che vedi.

Hai due scelte per risolvere questo problema (supponendo che si vuole attaccare con un singolo thread):

  1. Usa scheduleWithFixedDelay piuttosto che scheduleAtFixedRate. Se leggi attentamente javadoc, vedrai che scheduleWithFixedDelay attenderà 50 millisecondi tra la fine di una attività e l'inizio della successiva, quindi non si "sovrapporrà" mai, anche se una di queste richiede molto tempo. Al contrario, scheduleAtFixedRate proverà ad eseguire ogni 50 millisecondi, indipendentemente dal tempo impiegato da ciascuno.

  2. Modificare il modo in cui l'executor gestisce gli errori da eseguire.L'impostazione predefinita è di registrare un'eccezione, ma puoi dire ad essa di ignorarla, ad esempio. Dai uno sguardo alle sottoclassi di java.util.concurrent.RejectedExecutionHandler, ad esempio DiscardPolicy, che elimina semplicemente l'attività che non può essere eseguita. È possibile utilizzarli direttamente costruendo ScheduledThreadPoolExecutor e passando il gestore al costruttore, anziché utilizzare la classe di fabbrica Executors.

Sospetto che l'opzione (1) sia ciò che desideri.

+0

Grazie! Funziona – Andrey

+3

@skaffman: in realtà è esattamente l'opposto di quello che hai detto in 1. :) javadoc: scheduleAtFixedRate: se una qualsiasi esecuzione di questa operazione richiede più tempo del suo periodo, le esecuzioni successive potrebbero iniziare in ritardo, ma non verranno eseguite simultaneamente – radio

4

Questa eccezione verrà generata quando sia:

  1. Si hanno arresto l'Esecutore
  2. limiti del Executor per la sua coda di lavoro o le discussioni massimi sono stati superati.

Presumo che quest'ultimo stia accadendo. Quando si esegue l'attività e richiede molto tempo, le successive operazioni pianificate non possono essere eseguite perché non ci sono abbastanza thread disponibili nel pool.

O:

  1. Usa usare una dimensione piscina più grande o utilizzare cachedThreadPool
  2. cambiare la politica di rifiuto di utilizzare ad esempio ThreadPoolExecutor.CallerRunsPolicy
  3. Creazione di un esecutore separata per l'esecuzione dei compiti di lungo periodo e corsa questi dal tuo compito programmato. In realtà è possibile farlo utilizzando la stessa istanza dell'Executor, purché si aumenti la dimensione del pool.

Vedi anche ThreadPoolExecutor javadoc

+0

Come usare cacheThreadPool nella mia situazione? executor.scheduleAtFixedRate (myTask, 0, 50, TimeUnit.MILLISECONDS); Come è possibile modificare la politica di rifiuto di ThreadPoolExecutor? Grazie – Andrey