Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8071638

[JAVADOC] Buggy example in javadoc for afterExecute to access a submitted job's Throwable

XMLWordPrintable

        A DESCRIPTION OF THE PROBLEM :
        Example implementation given for afterExecute method invokes 'get' method of 'Future' without verifying the state of 'Future'. In case of a periodically scheduled future task like the ones created using 'scheduleAtFixedRate(...)' or 'scheduleWithFixedDelay(...)' methods of 'ScheduledThreadPoolExecutor', future is run and reset by the scheduled thread pool executor. As a result, post a normal execution of runnable, the call to Future's get() method will lead to an indefinite wait.

        Instead, the call to Future's get() method should only be made if Future's isDone() method returns true.

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        Method invoked upon completion of execution of the given Runnable. This method is invoked by the thread that executed the task. If non-null, the Throwable is the uncaught RuntimeException or Error that caused execution to terminate abruptly.

        This implementation does nothing, but may be customized in subclasses. Note: To properly nest multiple overridings, subclasses should generally invoke super.afterExecute at the beginning of this method.

        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. If you would like to trap both kinds of failures in this method, you can further probe for such cases, as in this sample subclass that prints either the direct cause or the underlying exception if a task has been aborted:

         class ExtendedExecutor extends ThreadPoolExecutor {
           // ...
           protected void afterExecute(Runnable r, Throwable t) {
             super.afterExecute(r, t);
             if (t == null && r instanceof Future<?> && ((Future<?>) r).isDone()) {
               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);
           }
         }

        Parameters:
            r - the runnable that has completed
            t - the exception that caused termination, or null if execution completed normally
        ACTUAL -
        Method invoked upon completion of execution of the given Runnable. This method is invoked by the thread that executed the task. If non-null, the Throwable is the uncaught RuntimeException or Error that caused execution to terminate abruptly.

        This implementation does nothing, but may be customized in subclasses. Note: To properly nest multiple overridings, subclasses should generally invoke super.afterExecute at the beginning of this method.

        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. If you would like to trap both kinds of failures in this method, you can further probe for such cases, as in this sample subclass that prints either the direct cause or the underlying exception if a task has been aborted:

         class ExtendedExecutor extends ThreadPoolExecutor {
           // ...
           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);
           }
         }

        Parameters:
            r - the runnable that has completed
            t - the exception that caused termination, or null if execution completed normally

        URL OF FAULTY DOCUMENTATION :
        http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html#afterExecute(java.lang.Runnable,%20java.lang.Throwable)


        line to fix:
        http://hg.openjdk.java.net/jdk9/dev/jdk/file/7c6d6f1b7a56/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java#l1971

              martin Martin Buchholz
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

                Created:
                Updated:
                Resolved: