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

example afterExecute for ScheduledThreadPoolExecutor hangs

XMLWordPrintable

        FULL PRODUCT VERSION :
        JDK 1.7.0_02

        ADDITIONAL OS VERSION INFORMATION :
        Windows 7 x64

        A DESCRIPTION OF THE PROBLEM :
        When using a subclassed ScheduledThreadPoolExecutor with the example afterExecute method provided in the documentation, the implementation will hang on the
        Object result = ((Future<?>) r).get();
        line. The reason is as follows:
        for a scheduledThreadPool afterExecute is called after every timed execution ( this is possible another bug as various docs on the internet imply it is only called after the task is cancelled or fully completed, but that is another issue) however, the call to get() tries to get a shared lock which only succeeds once the task has completed. Therefore afterExecute hangs on this lock indefinitely as the task is rescheduled for another execution.


        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        The provided code fails each time it is run



        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        The program should continue to print "something" every 1 second for ever (or until stopped)
        ACTUAL -
        something is printed 5 times (once for each thread in the pool) before hanging indefinitely.

        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------

        package tasktests;

        import java.util.concurrent.CancellationException;
        import java.util.concurrent.ExecutionException;
        import java.util.concurrent.Future;
        import java.util.concurrent.ScheduledExecutorService;
        import java.util.concurrent.ScheduledThreadPoolExecutor;
        import java.util.concurrent.TimeUnit;

        public class TaskTests {

            private static class MyExecutor extends ScheduledThreadPoolExecutor {
                public MyExecutor(){
                    super(5);
                }
                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(); // << hangs here
                                result=null;
                            } 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);
                    }
                }
            }

            private static class FailTask implements Runnable {
                public void run(){
                    System.out.println("something");
                }
            }
            public static void main(String[] args) {
                exec=Executors.newScheduledThreadPool(5);
                ScheduledExecutorService exec=new MyExecutor();
                exec.scheduleWithFixedDelay(new FailTask(), 0, 1000, TimeUnit.MILLISECONDS);
            }
        }
        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :

        A work around is to put a call to isDone() in the code before calling get as follows:


        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()
                                result=null;
                            } 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);
                    }
                }

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

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: