2009-12-21 14 views
7

J'ai ce problème, jeJava: SingleThreadScheduledExecutor & java.util.concurrent.RejectedExecutionException

private ScheduledExecutorService executor = 
    Executors.newSingleThreadScheduledExecutor(); 

et tâche qui est créé toutes les 50 millliseconds:

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

myTask prennent parfois un certain temps pour terminer (comme 2 ou 3 secondes), mais newSingleThreadScheduledExecutor garantit que la prochaine myTask planifiée attendra jusqu'à ce que la tâche en cours se termine.

Cependant, je reçois cette erreur de temps en temps:

Execute: java.util.concurrent.RejectedExecutionException

Que dois-je faire? Merci

+0

S'il vous plaît être plus précis sur ce que signifie yyou par "de temps en temps". Cette exception ne doit être levée qu'au moment de l'appel de 'execute()' sur ExecutorService. –

+0

En fait, RejectedExecutionException peut être lancé par executor.scheduleAtFixedRate() –

+0

@Andrey, vous devez nous donner beaucoup plus d'informations, en commençant par une trace de pile montrant l'exception. –

Répondre

11

Pensez à ce que l'exécuteur testamentaire fait. Il exécute une seule tâche toutes les 50 millisecondes, selon vos instructions. En supposant que cette tâche dure moins de 50 millisecondes, tout va bien. Cependant, de temps en temps, il faut 2-3 secondes pour fonctionner. Lorsque cela se produit, l'exécuteur tente toujours d'exécuter toutes les 50 millisecondes, mais parce qu'il n'a qu'un seul thread, il ne peut pas, et rejette les exécutions qui sont déclenchées pendant que votre tâche de longue durée continue. Cela provoque l'exception que vous voyez.

Vous avez deux choix pour résoudre ce (en supposant que vous voulez coller avec un seul fil):

  1. Utilisez scheduleWithFixedDelay plutôt que scheduleAtFixedRate. Si vous lisez attentivement le javadoc, vous verrez que scheduleWithFixedDelay attendra 50 millisecondes entre la fin d'une tâche et le début de la suivante, de sorte qu'il ne se chevauchera jamais, même si l'un d'entre eux prend beaucoup de temps. En revanche, scheduleAtFixedRate essaiera d'exécuter toutes les 50 millisecondes, quelle que soit la longueur de chacun d'entre eux.

  2. Modifiez la façon dont l'exécuteur gère les échecs à exécuter.La valeur par défaut est de consigner une exception, mais vous pouvez lui indiquer de l'ignorer, par exemple. Jetez un oeil aux sous-classes de java.util.concurrent.RejectedExecutionHandler, par exemple DiscardPolicy, qui supprime simplement silencieusement la tâche qui ne peut pas être exécutée. Vous pouvez les utiliser en construisant directement ScheduledThreadPoolExecutor et en transmettant le gestionnaire au constructeur, plutôt que d'utiliser la classe Executors.

Je suppose que l'option (1) est ce que vous voulez.

+0

Merci! Cela fonctionne – Andrey

+3

@skaffman: en fait c'est exactement le contraire de ce que vous avez dit dans 1. :) javadoc: scheduleAtFixedRate: Si toute exécution de cette tâche prend plus de temps que sa période, alors les exécutions suivantes peuvent commencer en retard, mais ne seront pas exécutées simultanément – radio

4

Cette exception sera levée lorsque:

  1. Vous avez l'arrêt Exécuteur
  2. limites de l'exécuteur testamentaire pour sa file d'attente de travail ou les discussions maximales ont été dépassées.

Je suppose que ce dernier se produit. Lorsque vous exécutez votre tâche et que cela prend beaucoup de temps, les tâches planifiées suivantes ne peuvent pas être exécutées car le nombre de threads disponibles dans le pool est insuffisant.

Soit:

  1. Utilisez utiliser une taille plus grande piscine ou utiliser cachedThreadPool
  2. Modifier la politique de rejet à utiliser par exemple ThreadPoolExecutor.CallerRunsPolicy
  3. Créer un Exécuteur séparé pour l'exécution des longues tâches d'exécution et de course ceux-ci de votre tâche planifiée. En réalité, vous pouvez le faire en utilisant la même instance d'Executor à condition d'augmenter la taille du pool.

Voir aussi ThreadPoolExecutor javadoc

+0

Comment utiliser cachedThreadPool dans ma situation? executor.scheduleAtFixedRate (myTask, 0, 50, TimeUnit.MILLISECONDS); Comment est-il possible de modifier la politique de rejet ThreadPoolExecutor? Merci – Andrey