views:

58

answers:

4

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();
    }
}
+4  A: 

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;
    }
}
Mark Peters
`UncaughExceptionHandler` does not work with scheduled runnables.
Willi
@Willi: Let me verify and then I'll delete it if I confirm.
Mark Peters
Undeleting since it still seems to be useful for non-scheduled thread pool executors.
Mark Peters
+1  A: 

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.

Michael
`ScheduledThreadPoolExecutor` is in `java.util.concurrent`...
Willi
+2  A: 

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.

Colin Hebert
How does that work for subsequent invocations? e.g. how do you get a future for the second invocation, after the first has returned successfully?
Mark Peters
@Mark If one execution failed, there will be no second (or third, ...) execution. Copied from the original javadoc: *If any execution of the task encounters an exception, subsequent executions are suppressed.*
Willi
@Willi: Then I guess I'm confused about the OP's statement "seems to be eating Exceptions..." if it's only ever run once.
Mark Peters
@Mark -- The problem I was having is that a repeating Scheduled task was throwing an exception -- then the thread executing that task just died with no indication that a thread in my thread pool encountered a problem.
Ivan
@Mark Good point. Maybe he meant one Exception from multiple runs?
Willi
+4  A: 

I wrote a small post about this problem a while ago. You have two options:

  1. Use the solution provided by Colin Herbert or
  2. 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.

Willi
Alright I confirmed it and deleted my answer. Thanks! Feel free to modify your step 2 to go into details.
Mark Peters
Actually I tried your #2 and couldn't get it to work. The exception was caught well above my try/catch block in the delegating Runnable, so this seems to succumb to the same problem as the UncaughtExceptionHandler.
Mark Peters
I just accepted this -- But Mark is saying Decorating the submitted tasks with a try/catch isn't ....I'm gonna try this out.
Ivan
@Mark @Ivan Interesting. Mark, could you post your code?
Willi
@Ivan: I'm not saying that wouldn't work. Willi seemed at first (through his reference to my suggestion) to be suggesting that you wrap the Runnable submitted to `ThreadFactory.newThread(Runnable)` with a Runnable that catches the exception. That won't work. Wrapping each Runnable *submitted* to the executor *will* work but has little to do with my suggestions, so that link should probably be removed for clarity.
Mark Peters
@Mark You are right, i screwed that up. Editing...
Willi