245 votes

La gestion des exceptions de Java ExecutorService tâches

Je suis en train d'utiliser Java ThreadPoolExecutor de la classe à exécuter un grand nombre de poids lourds tâches avec un nombre fixe de threads. Chacune de ces tâches a de nombreux endroits au cours de laquelle il peut échouer à cause des exceptions.

J'ai sous-classé ThreadPoolExecutor et j'ai remplacé le "afterExecute" méthode qui est censée fournir toutes les exceptions rencontrées pendant l'exécution de la tâche. Cependant, je n'arrive pas à le faire fonctionner.

Par exemple:

public class ThreadPoolErrors extends ThreadPoolExecutor {
    public ThreadPoolErrors() {
        super(  1, // core threads
                1, // max threads
                1, // timeout
                TimeUnit.MINUTES, // timeout units
                new LinkedBlockingQueue() // work queue
        );
    }

    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        if(t != null) {
            System.out.println("Got an error: " + t);
        } else {
            System.out.println("Everything's fine--situation normal!");
        }
    }

    public static void main( String [] args) {
        ThreadPoolErrors threadPool = new ThreadPoolErrors();
        threadPool.submit( 
                new Runnable() {
                    public void run() {
                        throw new RuntimeException("Ouch! Got an error.");
                    }
                }
        );
        threadPool.shutdown();
    }
}

La sortie de ce programme est "Tout va bien--situation normale!" même si la seule Praticable soumis pool de threads, déclenche une exception. La moindre idée de ce qui se passe ici?

Merci!

266voto

skaffman Points 197885

Si vous souhaitez traiter les exceptions levées par la tâche, il est généralement préférable d'utiliser des Callable plutôt que d' Runnable.

Callable.call() est autorisé à jeter checked exceptions, et ceux-ci sont renvoyés vers le thread appelant:

Callable task = ...
Future future = executor.submit(task);
try {
   future.get();
} catch (ExecutionException ex) {
   ex.getCause().printStackTrace();
}

Si Callable.call() lance une exception, ce sera enveloppé dans un ExecutionException et jeté en Future.get().

C'est probablement nettement préférable de sous-classement ThreadPoolExecutor. Il vous donne également la possibilité de re-présenter la tâche si l'exception est récupérable.

172voto

nos Points 102226

À partir de la docs:

Remarque: Lorsque des actions sont enfermés dans des tâches (telles que FutureTask) explicitement ou par des méthodes telles que soumettre, ces objets de capture et maintenir calcul des exceptions, et de sorte qu'ils ne causent pas de brusque résiliation, et l'interne les exceptions ne sont pas transmises à cette la méthode.

Lorsque vous soumettez un Exécutable, il va avoir enveloppé dans un Avenir.

Votre afterExecute devrait être quelque chose comme ceci:

  protected void afterExecute(Runnable r, Throwable t) {
      super.afterExecute(r, t);
      if (t == null && r instanceof Future<?>) {
        try {
          Future<?> future = (Future<?>) r;
          if (future.isDone())
            future.get();
        } catch (CancellationException ce) {
            t = ce;
        } catch (ExecutionException ee) {
            t = ee.getCause();
        } catch (InterruptedException ie) {
            Thread.currentThread().interrupt(); // ignore/reset
        }
      }
      if (t != null)
               System.out.println(t);
     }
 }

20voto

Drew Wills Points 4768

L'explication de ce comportement est à droite dans la javadoc pour afterExecute:

Remarque: Lorsque des actions sont enfermés dans des tâches (telles que FutureTask) explicitement ou par des méthodes telles que soumettre, ces objets de capture et maintenir calcul des exceptions, et de sorte qu'ils ne causent pas de brusque résiliation, et l'interne les exceptions ne sont pas transmises à cette la méthode.

6voto

yegor256 Points 21737

Je suis à l'aide d' VerboseRunnable classe de jcabi-journal, qui avale toutes les exceptions et les journaux. Très pratique, par exemple:

import com.jcabi.log.VerboseRunnable;
scheduler.scheduleWithFixedDelay(
  new VerboseRunnable(
    Runnable() {
      public void run() { 
        // the code, which may throw
      }
    },
    true // it means that all exceptions will be swallowed and logged
  ),
  1, 1, TimeUnit.MILLISECONDS
);

3voto

Lambodar Points 93

Pour la gestion des exceptions dans ExecutorService vous avez à prendre l'avantage de Appelable et de l' Avenir.

S'il vous plaît regarder la vidéo ci-dessous pour plus de détails. Espérons que cela que cela va vous aider de nos.

VIDÉO: Callable et Avenir(11 min)

Vous n'obtiendrez jamais de doute de nouveau!!! :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X