3

EDIT:

How to catch an Exception from a thread - this is not a duplication. The link refers to direct thread (son thread) which it's not the case here! We are talking about indirect (grandson thread). The son thread is a closed JAR (I do not have write access)


I have the following method: f1 which I don't have write access to (It's a closed JAR).

f1 creates and runs a task on new thread which throws exception. On the main method, I must call f1 on new thread. I need to be able to catch all the exceptions which were thrown from child threads of f1.

In other words, how do I catch exceptions from grandson thread without changing the son thread.

main method opens new thread and call:
      |
      V
f1 method opens new thread and call:
      |
      V
anonymous method which throws exception

Example code:

private static void f1() {
    Executors.newSingleThreadExecutor()
            .submit(() -> {
                try {
                    throw new Exception("exception from anonymous thread");
                } catch (Exception e) {
                    e.printStackTrace();
                    throw e;
                }
            });

}

public void main() {
    final Future<?> submit = Executors.newSingleThreadExecutor()
            .submit(() -> f1());
    try {
        submit.get();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
}
Ida Amit
  • 1,411
  • 2
  • 13
  • 27
  • ExecutionException will have the thrown exception as root cause – guido Apr 09 '18 at 08:17
  • @GhostCat This is not the same question! Your duplication refers to directed thread (son thread) which it's not the case here! We are talking about indirect (grandson thread) – Ida Amit Apr 09 '18 at 08:20
  • @GhostCat The OP does not ask the same question. Your link refers to a question which has to write access to the code and here the OP doesn't have. – Stav Alfi Apr 09 '18 at 08:30
  • @ᴳᵁᴵᴰᴼ I checked, It does not. – Stav Alfi Apr 09 '18 at 10:57
  • @StavAlfi It does not because the method `f1` swallows all the exceptions, it doesn't throw any exception itself, that's why in the main method we can catch nothing. – grape_mao Apr 09 '18 at 11:42
  • @grape_mao do you imply that, in case I can't edit `f1`, there isn't any solution for this problem ? – Ida Amit Apr 09 '18 at 12:18
  • @AlmaShvartz I can't say that for sure, maybe some hack on bytecode level. If the design of `f1` doesn't give you access to the executor/thread, nor to the task, then it doesn't want you to care about the execution. But for me it's a bad design. – grape_mao Apr 09 '18 at 12:27
  • 5
    No chance. Keep in mind that by the time, your `main` method’s `submit.get()` returns, there is no guaranty that the asynchronous task spawned by `f1()` has even finished, not to speak of having delivered an inspectable exception. Even `UncaughtExceptionHandler` of the linked answer won’t help, as the exception is not uncaught. When `submit` is used, the job gets wrapped in a future which will catch any exception, so it can be propagated if `get` is called. Since no-one keeps a reference to that future, the exception is lost. Without modifying `f1()`, there’s no way. – Holger Apr 09 '18 at 13:01

1 Answers1

1

There is no general answer to this question. In this case exception is handled inside Executor. You can do one of

  • catch all exceptions that may occur inside task and return meaningfull status for exceptions caught

  • if task was submitted as Callable<?> then get on returned Future<?> will throw ExecutionException if task completed with exception

  • for uncaught exceptions you could set Uncaught Exception Handler on Thread Factory used by Executor

  • ThreadPoolExecutor has afterExecute(Runnable r, Throwable t) method with can handle uncaught exceptions from tasks

Bartosz Bilicki
  • 12,599
  • 13
  • 71
  • 113