13

A discussion in Code Review chat determined the following behaviour from a ScheduledExecutorService:

A task scheduled to run fails with a 'serious' problem, but there's no report, exception, or log of the problem. In other contexts, the application would normally terminate with an Error. In the context of the ScheduledExecutorService, though, there is no Exception/Error 'handling' at all.

First, to fabricate a problem. The following class has a static initializer that is guaranteed to fail:

public class InitializerFault {
    
    private static final int value = Integer.parseInt("fubar");
    
    @Override
    public String toString() {
        return "" + value;
    }

}

When run as:

public static void main(String[] args) {
    System.out.println(new InitializerFault());
}

it produces (which is exactly what I would expect):

Exception in thread "main" java.lang.ExceptionInInitializerError
    at SimpleHandler.main(SimpleHandler.java:5)
Caused by: java.lang.NumberFormatException: For input string: "fubar"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:580)
    at java.lang.Integer.parseInt(Integer.java:615)
    at InitializerFault.<clinit>(InitializerFault.java:4)
    ... 1 more

But, when run as:

private static final Thread buildThread(Runnable r) {
    Thread t = new Thread(r, "TestThread");
    t.setDaemon(true);
    System.out.println("Built thread " + t);
    return t;
}
public static void main(String[] args) throws InterruptedException {
    // use a thread factory to create daemon threads ... can be non-daemon as well.
    ScheduledExecutorService ses = Executors.newScheduledThreadPool(
           2, (r) -> buildThread(r));
    ses.scheduleAtFixedRate(
           () -> {System.out.println(new InitializerFault());},
           500, 1000, TimeUnit.MILLISECONDS);
    Thread.sleep(3000);
    System.out.println("Exiting");
}

it produces just:

Built thread Thread[TestThread,5,main]
Exiting

There is no mention of any error, no fault, no dump, nothing. This ExceptionInInitializerError has resulted in a complicated real-life debug process, where the problem was very hard to isolate.

Two questions:

  1. is this expected Java behaviour, that Errors in the Executors are 'ignored'?
  2. what's the right way to handle this situation?
Community
  • 1
  • 1
rolfl
  • 17,539
  • 7
  • 42
  • 76
  • This can help you [Exception handling in ThreadPools](http://stackoverflow.com/questions/3875739/exception-handling-in-threadpools/3875968#3875968) – Tkachuk_Evgen Dec 03 '14 at 16:17

1 Answers1

4

ScheduledExecutorService.scheduleAtFixedRate returns a ScheduledFuture. If we call ScheduledFuture.get() the thread will block and wait for the periodic task completion, which may happen upon task cancellation or if the task throws an exception. In the latter case get() will throw java.util.concurrent.ExecutionException with wrapped original exception

Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
  • 4
    Right, I have now tried that, and (of course) you're right, it does. While your answer is right, it's an ugly solution.... The real task itself does regular exception handling with try/catch blocks, but does not trap the Error... Additionally, 'waiting' on the main thread (or a non Executor thread) is not very practical. If I wanted to block there, I would not have used the delay. It's not your fault, but your suggested solution is 'ugly'. – rolfl Dec 03 '14 at 14:22