How to catch exceptions in FutureTask

前端 未结 5 735
小蘑菇
小蘑菇 2020-12-06 04:42

After finding that FutureTask running in a Executors.newCachedThreadPool() on Java 1.6 (and from Eclipse) swallows exceptions in the Runnable

相关标签:
5条回答
  • 2020-12-06 04:55

    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.

    0 讨论(0)
  • 2020-12-06 04:59

    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);
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-06 05:02

    I have looked at the source code of FutureTask and could not find where setException is being called.
    There is an innerSetException method from FutureTask.Sync (inner class of FutureTask) that is being called in case of an Throwable being thrown by the run method. This method is also being called in setException.
    So it seams like the javadoc is not correct (or very hard to understand...).

    0 讨论(0)
  • 2020-12-06 05:02

    There are three standard ways and one improvised way. 1. use UncaughtExceptionHandler, set the UncaughtExceptionHandler for the created thread as

    Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                public void uncaughtException(Thread t, Throwable ex) {..}}
    

    *But the limitation is it catches the exception thrown by thread but in case of future task, it is swallowed. 2. use afterExecute after making a custom threadpoolexecutor with hook that has been provided specially for this purpose. Looking through the code of ThreadpoolExecutor, via submit > execute (there is a workQueue, workQueue.offer), the tasks are added to the work queue

       final void runWorker(Worker arg0) {
      Thread arg1 = Thread.currentThread();
      Runnable arg2 = arg0.firstTask;
      ..
         while(arg2 != null || (arg2 = this.**getTask()**) != null) {
            arg0.lock();
            ..
            try {
               this.beforeExecute(arg1, arg2);
               Object arg4 = null;
               try {
                  arg2.run();
               } catch (RuntimeException arg27) {
                 ..
               } finally {
                  this.**afterExecute**(arg2, (Throwable)arg4);
               }
    
      }
    
    getTask() {..
     this.workQueue.**poll**();
    ..}
    
    1. Then, the third is using simple try catch inside the call method but you can not catch the exception outside here.

    2. The workaround is calling all the call methods from a call method of a TaskFactory, a factory that releases callables.

    0 讨论(0)
  • 2020-12-06 05:09

    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

    0 讨论(0)
提交回复
热议问题