web-dev-qa-db-fra.com

Gestion des exceptions dans ThreadPools

J'ai un ScheduledThreadPoolExecutor qui semble manger des exceptions. Je veux que mon service d'exécuteur m'informe si un Runnable soumis lève une exception.

Par exemple, j'aimerais que le code ci-dessous affiche au moins le stackTrace de IndexArrayOutOfBoundsException

threadPool.scheduleAtFixedRate(
  new Runnable() {
    public void run() {
      int[] array = new array[0];
      array[42] = 5;
    }
  },
  1000,
  1500L,
  TimeUnit.MILLISECONDS);

Comme question secondaire. Existe-t-il un moyen d'écrire un bloc catch catch général pour un ScheduledThreadPoolExecutor?

////////// FIN DE LA QUESTION ORIGINALE //////////////

Comme suggéré, le décorateur suivant fonctionne bien.

public class CatcherTask implements Runnable{

    Runnable runMe;

    public CatcherTask(Runnable runMe) {
        this.runMe = runMe;
    }

    public void run() {
        try {
            runMe.run();
        } catch (Exception ex){
            ex.printStackTrace();
        }
    }
}
43
Ivan

J'ai écrit un petit post sur ce problème il y a quelque temps. Vous avez deux options:

  1. Utilisez la solution fournie par Colin Herbert ou
  2. utiliser une version modifiée de Mark Peters solution mais au lieu d'attribuer un UncaughtExceptionHandler vous enveloppez chaque runnable soumis dans une propre runnable qui exécute (appelle run) le vrai exécutable dans un bloc try-catch.

[~ # ~] modifier [~ # ~]
Comme l'a souligné Mark, il est important d'encapsuler le Runnable passé à ScheduledExecutorService au lieu de celui passé au ThreadFactory.

24
whiskeysierra

Avertissement : cette méthode ne s'applique pas aux exécuteurs de pool de threads planifiés . Cette réponse a été annulée pour sa pertinence pour les autres exécuteurs de pool de threads. Voir réponse de Willi .

Remplacez ThreadFactory pour donner à Threads un UncaughtExceptionHandler:

ThreadPoolExecutor exec = new ThreadPoolExecutor...;

exec.setThreadFactory(new ExceptionCatchingThreadFactory(exec.getThreadFactory()));
//go on to submit tasks...


private static class ExceptionCatchingThreadFactory implements ThreadFactory {
    private final ThreadFactory delegate;

    private ExceptionCatchingThreadFactory(ThreadFactory delegate) {
        this.delegate = delegate;
    }

    public Thread newThread(final Runnable r) {
        Thread t = delegate.newThread(r);
        t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                e.printStackTrace();  //replace with your handling logic.
            }
        });
        return t;
    }
}
13
Mark Peters

Vous pouvez utiliser la méthode get() de Future que vous obtenez en appelant scheduleAtFixedRate(). Il lancera un ExecutionException si une exception s'est produite lors de l'exécution du thread.

5
Colin Hebert

Vous pouvez également utiliser un ThreadPoolTaskScheduler du Spring Framework , qui expose une méthode pour définir un gestionnaire d'erreurs et fait tout l'habillage pour vous. Le comportement par défaut dépend du type de tâche:

Si le ErrorHandler fourni n'est pas nul, il sera utilisé. Sinon, les tâches répétitives auront des erreurs supprimées par défaut tandis que les tâches ponctuelles auront des erreurs propagées par défaut car ces erreurs peuvent être attendues via le Future retourné. Dans les deux cas, les erreurs seront enregistrées.

Si vous souhaitez uniquement utiliser la partie enveloppante et non le TaskScheduler, vous pouvez utiliser

TaskUtils.decorateTaskWithErrorHandler(task, errorHandler, isRepeatingTask)

que le TaskScheduler utilise en interne.

3
Johan Boberg

Vous pouvez sous-classer ScheduledThreadPoolExecutor et remplacer la méthode afterExecute pour gérer les exceptions et les erreurs pour tout type de Runnable que vous soumettez.

2
mryan