Why is the exception null in ThreadPoolExecutor afterExecute ()?

I want to handle exceptions thrown by workflows in the ThreadPoolExecutor#afterExecute() method. I currently have this code:

 public class MyExecutor extends ThreadPoolExecutor { public static void main(String[] args) { MyExecutor threadPool = new MyExecutor(); Task<Object> task = new Task<>(); threadPool.submit(task); } public MyExecutor() { super(4, 20, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(4000)); } @Override protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); System.out.println("in afterExecute()"); if (t != null) { System.out.println("exception thrown: " + t.getMessage()); } else { System.out.println("t == null"); } } private static class Task<V> implements Callable<V> { @Override public V call() throws Exception { System.out.println("in call()"); throw new SQLException("testing.."); } } } 

If I run the code, I get the output:

 in call() in afterExecute() t == null 

Why is the Throwable t null parameter in afterExecute() ? Shouldn't there be an instance of SQLException ?

+8
java multithreading threadpool threadpoolexecutor futuretask
source share
2 answers

This is the expected behavior.

Quoting afterExecute Javadoc:

If non-empty, Throwable is a fuzzy RuntimeException or Error exception that causes execution to abruptly abort.

This means that the throwing instance will be a RuntimeException or Error , and not an Exception . Since SQLException is a checked exception, it will not be passed to afterExecute .

Something else happens here as well (quoting Javadoc):

Note. . When actions are enclosed in tasks (for example, FutureTask ) either explicitly or using methods such as submit, these task objects catch and support computational exceptions, and therefore they do not cause abrupt terminations, and internal exceptions are not passed to this method.

In your example, the task is in FutureTask , since you are sending Callable , so you are in this case. Even you change your code to throw a RuntimeException if RuntimeException is not afterExecute . Javadoc gives a sample code to handle this, which I am copying here for reference:

 protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); if (t == null && r instanceof Future) { try { Object result = ((Future) r).get(); } catch (CancellationException ce) { t = ce; } catch (ExecutionException ee) { t = ee.getCause(); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); // ignore/reset } } if (t != null) System.out.println(t); } 
+7
source share

This is an alternative way to do this. Hint from here

 package com.autonomy.introspect.service; import java.sql.SQLException; import java.util.concurrent.*; public class MyExecutor extends ThreadPoolExecutor { public static void main(String[] args) { MyExecutor threadPool = new MyExecutor(); Task<Object> task = new Task<Object>(); Future<Object> futureTask = threadPool.submit(task); try { System.out.println(futureTask.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { System.out.println("exception thrown: " + e.getMessage()); } } public MyExecutor() { super(4, 20, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(4000)); } @Override protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); System.out.println("in afterExecute()"); if (t != null) { System.out.println("exception thrown: " + t.getMessage()); } else { System.out.println("t == null"); } } private static class Task<V> implements Callable<V> { @Override public V call() throws Exception { System.out.println("in call()"); throw new SQLException("testing.."); } } } 

Using afterExecute for another purpose.

 This class provides protected overridable beforeExecute(java.lang.Thread, java.lang.Runnable) and afterExecute(java.lang.Runnable, java.lang.Throwable) methods that are called before and after execution of each task. These can be used to manipulate the execution environment; for example, reinitializing ThreadLocals, gathering statistics, or adding log entries. Additionally, method terminated() can be overridden to perform any special processing that needs to be done once the Executor has fully terminated. If hook or callback methods throw exceptions, internal worker threads may 

in turn fails and abruptly stops.

+1
source share

All Articles