I have a ScheduledThreadPoolExecutor that seems to be eating Exceptions. I want my executor service to notify me if a submitted Runnable throws an exception.
For example, I'd like the code below to at the very least print the IndexArrayOutOfBoundsException's stackTrace
threadPool.scheduleAtFixedRate(
new Runnable() {
public void run() {
int[] array = new array[0];
array[42] = 5;
}
},
1000,
1500L,
TimeUnit.MILLISECONDS);
As a side question. Is there a way to write a general try catch block for a ScheduledThreadPoolExecutor?
//////////END OF ORIGINAL QUESTION //////////////
As suggested the following Decorator works well.
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();
}
}
}
I wrote a small post about this problem a while ago. You have two options:
- Use the solution provided by Colin Herbert or
- use a modified version of Mark Peters solution but instead of assigning a
UncaughtExceptionHandler
you wrap each submitted runnable into a runnable of your own which executes (calls run
) the real runnable inside a try-catch-block.
EDIT
As pointed out by Mark, it's important to wrap the Runnable
passed to ScheduledExecutorService
instead of the one passed to the ThreadFactory
.
Warning: This method is not applicable to scheduled thread pool executors. This answer has been undeleted for its relevance to other thread pool executors. See Willi's answer.
Override the ThreadFactory
to give Threads an 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;
}
}
You can use the get()
method from the Future
you're getting by calling scheduleAtFixedRate()
. It will throw an ExecutionException
if an exeception occurred during the thread execution.
You could also use a ThreadPoolTaskScheduler
from the Spring Framework, which exposes a method to set an error handler and does all the wrapping for you. The default behavior depends on the type of task:
If the provided ErrorHandler
is not null, it will be used. Otherwise, repeating tasks will have errors suppressed by default whereas one-shot tasks will have errors propagated by default since those errors may be expected through the returned Future
. In both cases, the errors will be logged.
If you only want to use the wrapping part and not the TaskScheduler
you can use
TaskUtils.decorateTaskWithErrorHandler(task, errorHandler, isRepeatingTask)
which the TaskScheduler
uses internally.
You can subclass ScheduledThreadPoolExecutor and override the afterExecute method to handle exceptions and errors for any kind of Runnable that you submit.
Consider adding a static event in your ScheduledThreadPoolExecutor class that any of your tasks can call if an exception is thrown. That way, you can leverage that event to capture and handle the exceptions that occur within your threads.