Friday, February 20, 2015

Try-n-Catch your ScheduledThreadPoolExecutor task

MAKE SURE A try-catch block is placed within the run() method of every single task that is submitted to a ScheduledThreadPoolExecutor in case an unexpected exception gets thrown and results in the hanging of the entire executor.

To elaborate:

Below is the run() overriden in the ScheduledFutureTask:

         public void run() {
            boolean periodic = isPeriodic();
            if (! canRunInCurrentRunState(periodic ))
                cancel(false );
            else if ( !periodic )
                ScheduledFutureTask .super.run() ;
            else if ( ScheduledFutureTask. super. runAndReset()) {
                setNextRunTime();
                reExecutePeriodic(outerTask );
            }
        }

    void reExecutePeriodic(RunnableScheduledFuture<?> task ) {
        if (canRunInCurrentRunState(true)) {
            super. getQueue() .add (task );
            if (! canRunInCurrentRunState(true ) && remove( task))
                task. cancel( false);
            else
                ensurePrestart();
        }
    }

An exception that gets thrown at super.runAndRest() makes it fail to re-add the task back to the execution-queue, therefore in ThreadPoolExecutor.runWorker(), the current thread wil never be able to retrieve another task in next run of the while loop. (See below) and it will hang at getTask().

In java.concurrent.ThreadPoolExecutor

    final void runWorker( Worker w) {
        Thread wt = Thread. currentThread();
        Runnable task = w. firstTask;
        w. firstTask = null;
        w. unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            while (task != null || (task = getTask()) != null) {
                w. lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                if ((runStateAtLeast(ctl.get() , STOP) ||
                     (Thread .interrupted() &&
                      runStateAtLeast(ctl.get (), STOP ))) &&
                    !wt .isInterrupted())
                    wt. interrupt();
                try {
                    beforeExecute(wt, task) ;
                    Throwable thrown = null;
                    try {
                        task. run() ;
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task , thrown) ;
                    }
                } finally {
                    task = null;
                    w. completedTasks++;
                    w. unlock();
                }
            }
            completedAbruptly = false ;
        } finally {
            processWorkerExit(w , completedAbruptly);
        }
    }

5 Advanced Java Debugging Techniques Every Developer Should Know About

5 Advanced Java Debugging Techniques Every Developer Should Know About