Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to catch exceptions in FutureTask

Tags:

After finding that FutureTask running in a Executors.newCachedThreadPool() on Java 1.6 (and from Eclipse) swallows exceptions in the Runnable.run() method, I've tried to come up with a way to catch these without adding throw/catch to all my Runnable implementations.

The API suggests that overriding FutureTask.setException() should help in this:

Causes this future to report an ExecutionException with the given throwable as its cause, unless this Future has already been set or has been cancelled. This method is invoked internally by the run method upon failure of the computation.

However this method doesn't seem to be called (running with the debugger shows the exception is caught by FutureTask, but setException isn't called). I've written the following program to reproduce my problem:

public class RunTest {
    public static void main(String[] args) {
        MyFutureTask t = new MyFutureTask(new Runnable() {

            @Override
            public void run() {
                throw new RuntimeException("Unchecked exception");

            }
        });

        ExecutorService service = Executors.newCachedThreadPool();
        service.submit(t);
    }
}

public class MyFutureTask extends FutureTask<Object> {

    public MyFutureTask(Runnable r) {
        super(r, null);
    }

    @Override
    protected void setException(Throwable t) {
        super.setException(t);
        System.out.println("Exception: " + t);
    }
}

My main question is: How can I catch Exceptions thrown in a FutureTask? Why doesn't setException get called?

Also I would like to know why the Thread.UncaughtExceptionHandler mechanism isn't used by FutureTask, is there any reason for this?

like image 992
Thirler Avatar asked Aug 24 '10 09:08

Thirler


People also ask

How do you catch exceptions?

The try-catch is the simplest method of handling exceptions. Put the code you want to run in the try block, and any Java exceptions that the code throws are caught by one or more catch blocks. This method will catch any type of Java exceptions that get thrown. This is the simplest mechanism for handling exceptions.

Can we throw exception in catch?

When an exception is cached in a catch block, you can re-throw it using the throw keyword (which is used to throw the exception objects). Or, wrap it within a new exception and throw it.

How do you handle exceptions in run?

So even if run() throws exception the program cannot catch it. You should put thread execution result to some class level variable and then read it from there. Or alternatively use new API: executors and interface Callable that declares method call() that returns future result of the thread execution.

Where should you catch exceptions?

You should catch the exception when you are in the method that knows what to do. For example, forget about how it actually works for the moment, let's say you are writing a library for opening and reading files. Here, the programmer knows what to do, so they catch the exception and handle it.


3 Answers

setException probably isn't made for overriding, but is provided to let you set the result to an exception, should the need arise. What you want to do is override the done() method and try to get the result:

public class MyFutureTask extends FutureTask<Object> {      public MyFutureTask(Runnable r) {         super(r, null);     }      @Override     protected void done() {         try {             if (!isCancelled()) get();         } catch (ExecutionException e) {             // Exception occurred, deal with it             System.out.println("Exception: " + e.getCause());         } catch (InterruptedException e) {             // Shouldn't happen, we're invoked when computation is finished             throw new AssertionError(e);         }     } } 
like image 194
gustafc Avatar answered Oct 08 '22 09:10

gustafc


Have you tried using an UncaughtExceptionHandler?

  • You need to implement the UncaughtExceptionHandler interface.
  • To set an UncaughtExceptionHandler for pool threads, provide a ThreadFactory in the Executor.newCachedThreadPool(ThreadFactory) call.
  • You can set the UncaughtExceptionHandler for the created thread via setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)

Submit the tasks with ExecutorService.execute, because only exceptions thrown from tasks submitted with execute make it to the uncaught exception handler. For Tasks submitted with ExecutorService.submit any thrown exception is considered to be part of the task's return value. If a task submitted with submit terminates with an exception, it is rethrown when calling Future.get, wrapped in an ExecutionException

like image 45
Soundlink Avatar answered Oct 08 '22 09:10

Soundlink


A much better solution: Java FutureTask completion check

When you call futureTask.get() to retrieve the result of the computation it will throw an exception (ExecutionException) if the underlying Runnable/Callable threw an exception.

ExecutionException.getCause() will return the exception that the Runnable/Callable threw.

It will also throw a different exception if the Runnable/Callable was canceled.

like image 41
Christopher Alexander Avatar answered Oct 08 '22 10:10

Christopher Alexander