How to properly capture RuntimeExceptions from performers?

Say I have the following code:

ExecutorService executor = Executors.newSingleThreadExecutor(); executor.execute(myRunnable); 

Now, if myRunnable throws a RuntimeExcpetion , how can I catch it? One way would be to implement my own implementation of ThreadFactory before newSingleThreadExecutor() and set a custom uncaughtExceptionHandler for Thread that exits from it. Another way is to wrap myRunnable local (anonymous) Runnable containing try-catch -block. Perhaps there are other similar workarounds. But ... somehow it seems dirty, I feel that it should not be so difficult. Is there a clean solution?

+41
java concurrency runtimeexception executor
Nov 06 '09 at 2:30 p.m.
source share
5 answers

A clean solution is to use ExecutorService.submit() instead of execute() . This returns you Future , which you can use to get the result or task exception:

 ExecutorService executor = Executors.newSingleThreadExecutor(); Runnable task = new Runnable() { public void run() { throw new RuntimeException("foo"); } }; Future<?> future = executor.submit(task); try { future.get(); } catch (ExecutionException e) { Exception rootException = e.getCause(); } 
+53
Nov 06 '09 at 14:53
source share
— -

Why not call ExecutorService#submit() , get Future back, and then handle possible exceptions yourself when calling Future#get() ?

+10
Nov 06 '09 at 14:48
source share

Decorate runnable with another runnable, which catches exceptions at runtime and processes them:

 public class REHandler implements Runnable { Runnable delegate; public REHandler (Runnable delegate) { this.delegate = delegate; } public void run () { try { delegate.run (); } catch (RuntimeException e) { ... your fancy error handling here ... } } } executor.execute(new REHandler (myRunnable)); 
+8
Nov 06 '09 at 15:02
source share

skaffman is correct in that using submit is the cleanest approach. An alternative approach is to subclass ThreadPoolExecutor and override afterExecute(Runnable, Throwable) . If you follow this approach , do not call execute(Runnable) , not submit(Runnable) or afterExecute .

In the API description:

A method called upon completion of a given runnable. This method is called by the thread that completed the task. If not empty, Theft is a RuntimeException or Error , which caused the execution to RuntimeException suddenly.

Note. When actions are enclosed in tasks (such as FutureTask), either explicitly or using methods such as Send, these task objects catch and support computational exceptions and therefore they do not cause abrupt interruptions and internal methods are not transferred .

+5
Nov 06 '09 at 14:58
source share

a task ( Callable or Runnable ) sent to ThreadPoolExecutors will be converted to FuturnTask , contains a link called Callable , equal to the task you are sending. FuturnTask has its own run method as follows. All exceptions or throws thrown in c.call() will be caught and placed in a nickname named outcome . When calling the FuturnTask method get outcome will be selected

FuturnTask.run Source Code Jdk1.8

 public void run() { ... try { Callable<V> c = callable; if (c != null && state == NEW) { V result; boolean ran; try { result = c.call(); ran = true; } catch (Throwable ex) { result = null; ran = false; // save ex into `outcome` prop setException(ex); } if (ran) set(result); } } ... } 

if you want to catch the exception:

  1. 1. Scuffman answer
  1. 2. overwrite `afterExecute` when you new ThreadPoolExecutor
  @Override protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); Throwable cause = null; if (t == null && r instanceof Future) { try { ((Future<?>) r).get(); } catch (InterruptedException | ExecutionException e) { cause = e; } } else if (t != null) { cause = t; } if (cause != null) { // log error } } 
+2
Aug 25 '16 at 11:49
source share



All Articles