4

I am trying to run the following piece of code:

public static void main(String[] args){
    ScheduledExecutorService service = new ScheduledThreadPoolExecutor(2);

    Runnable r = new Runnable() {
        @Override
        public void run() {
            throw new RuntimeException();
        }
    };
    service.execute(r );
    ScheduledFuture<?> schedule = service.schedule(r, 0, TimeUnit.SECONDS);
    new Thread(r).run();
}

Regarding the above I have the following questions:

  1. Is there any way to catch and respond to exceptions happening on the executor's thread?
  2. Why is the exception from the thread created explicitly propagated to the main thread, but both executions using the executor service does not propagate that error? How can this error ever be discovered?

EDIT: One further question came to mind:

  1. How can i stop a given periodic task that I schedule, let's say after N repeats or N minutes?
Bober02
  • 15,034
  • 31
  • 92
  • 178
  • 1
    As by accident, I did a lecture on threads this day. I told my students that: If I feel mischievous I will have code for you to analyze on the exam. That code might contain t.run(), not t.start(). – Captain Giraffe Oct 09 '12 at 22:27
  • see my update it has been solved already – linski Oct 09 '12 at 22:27

2 Answers2

7

Question 2 is really easy - you're not actually starting a new thread, you're just calling run(), which runs synchronously in the original thread. You should be calling start(), at which point the exception won't be propagated back.

As for handling exceptions in a ScheduledExecutorService - if you call Future.get(), it will throw ExecutionException if the original task threw an exception, exposing the original exception as the cause:

Exception thrown when attempting to retrieve the result of a task that aborted by throwing an exception. This exception can be inspected using the Throwable.getCause() method.

If you need to respond to exceptions without blocking for the future to complete, you could wrap your "real" Runnable in another one which just delegated to the original's run() method, but with an appropriate try/catch block.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks, but is there a way to propagate the exception to the main/calling thread? – Bober02 Oct 09 '12 at 22:18
  • 2
    @Bober02: Using `Future.get()` is about it, really. After all, you wouldn't want the original thread to throw the exception at an arbitrary point in time, would you? – Jon Skeet Oct 09 '12 at 22:19
  • and how would you stop a perioic schedule after N attempts or N minutes? – Bober02 Oct 09 '12 at 22:23
6

You can catch it like this:

    ScheduledFuture<?> schedule = service.schedule(r, 0, TimeUnit.SECONDS);
    try {
        Object get = schedule.get();
    } catch (InterruptedException ex) {
        ex.printStackTrace();
    } catch (ExecutionException ex) {
        ex.printStackTrace();
    }

If the code running in (Scheduled)ExecutorService throws an exception it will be rethrown upon calling Future.get() wrapped into ExecutionException

EDIT:

about stopping scheduled tasks, it has been discussed and solved already.

Community
  • 1
  • 1
linski
  • 5,046
  • 3
  • 22
  • 35
  • OK, but what if I have a periodic scheduledFuture? WIll only the first exception be caught? WIll any subsequent executions be run? – Bober02 Oct 10 '12 at 08:31
  • The same. Yes. No, they [won't](http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ScheduledExecutorService.html#scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit)) – linski Oct 11 '12 at 06:45