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();
}
}
}
J'ai écrit un petit post sur ce problème il y a quelque temps. Vous avez deux options:
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
.
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;
}
}
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.
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.
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.