0 votes
1 view
in Java by (10.2k points)

I'm trying to use Java's ThreadPoolExecutor class to run a large number of heavy weight tasks with a fixed number of threads. Each of the tasks has many places during which it may fail due to exceptions.

I've subclassed ThreadPoolExecutor and I've overridden the afterExecute method which is supposed to provide any uncaught exceptions encountered while running a task. However, I can't seem to make it work.

For example:

public class ThreadPoolErrors extends ThreadPoolExecutor {

    public ThreadPoolErrors() {

        super(  1, // core threads

                1, // max threads

                1, // timeout

                TimeUnit.MINUTES, // timeout units

                new LinkedBlockingQueue<Runnable>() // work queue

        );

    }

    protected void afterExecute(Runnable r, Throwable t) {

        super.afterExecute(r, t);

        if(t != null) {

            System.out.println("Got an error: " + t);

        } else {

            System.out.println("Everything's fine--situation normal!");

        }

    }

    public static void main( String [] args) {

        ThreadPoolErrors threadPool = new ThreadPoolErrors();

        threadPool.submit( 

                new Runnable() {

                    public void run() {

                        throw new RuntimeException("Ouch! Got an error.");

                    }

                }

        );

        threadPool.shutdown();

    }

}

The output from this program is "Everything's fine--situation normal!" even though the only Runnable submitted to the thread pool throws an exception. Any clue to what's going on here?

Thanks!

1 Answer

0 votes
by (46.1k points)

From the docs:

Note: When actions are enclosed in tasks (such as FutureTask) either explicitly or via methods such as submit, these task objects catch and maintain computational exceptions, and so they do not cause abrupt termination, and the internal exceptions are not passed to this method.

When you submit a Runnable, it'll get wrapped in a Future.

Your afterExecute should be something like this:

public final class ExtendedExecutor extends ThreadPoolExecutor {

    // ...

    protected void afterExecute(Runnable r, Throwable t) {

        super.afterExecute(r, t);

        if (t == null && r instanceof Future<?>) {

            try {

                Future<?> future = (Future<?>) r;

                if (future.isDone()) {

                    future.get();

                }

            } catch (CancellationException ce) {

                t = ce;

            } catch (ExecutionException ee) {

                t = ee.getCause();

            } catch (InterruptedException ie) {

                Thread.currentThread().interrupt();

            }

        }

        if (t != null) {

            System.out.println(t);

        }

    }

}

Welcome to Intellipaat Community. Get your technical queries answered by top developers !


Categories

...