1

We are writing an app that uses a custom extension of the ThreadPoolExecutor to process a bunch of Runnables. In developing the app, we have run into OutOfMemoryErrors that occurred in our Runnable classes. But, instead of calling our afterExecute() like we would expect, the ThreadPoolExecutor just kept on trucking along.

I have pared down the code to a small, repeatable app.

ThreadPoolTest.java:

package org.codechimp.threadpool;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        LinkedBlockingQueue<Runnable> threadQueue = new LinkedBlockingQueue<Runnable>();
        ThreadPoolExecutor executor = new MyThreadPoolExecutor(10, Integer.MAX_VALUE, 2000, TimeUnit.MILLISECONDS, threadQueue);

        // Create a bunch of Runnables now...
        for (int i = 0; i < 10000; i++) {
            executor.execute(new MyRunnable(i));
            if (i % 100 == 0) {
                System.out.println("Queued " + i + " Runnables");
            }
            if (i % 1000 == 0) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException ignored) { }
            }
        }
        System.out.println("Done queing the Runnables.");

        while (!executor.isTerminated() && !executor.isTerminating() && executor.getQueue().size() > 0) {
            System.out.println(executor.getQueue().size() + " Runnables in the queue.");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ignored) { }
        }
        System.out.println("Runnable queue has stopped processing.");

        executor.shutdown();
        try {
            executor.awaitTermination(10, TimeUnit.MINUTES);
        } catch (InterruptedException ignored) { }
        System.out.println("Shutdown completed...exiting");
    }
}

MyThreadPoolExecutor.java:

package org.codechimp.threadpool;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MyThreadPoolExecutor extends ThreadPoolExecutor {
    public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
            long keepAliveTime, TimeUnit unit,
            BlockingQueue<Runnable> workQueue,
            RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
    }

    public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
            long keepAliveTime, TimeUnit unit,
            BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
            RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                threadFactory, handler);
    }

    public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
            long keepAliveTime, TimeUnit unit,
            BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                threadFactory);
    }

    public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
            long keepAliveTime, TimeUnit unit,
            BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        if (t != null) {
            System.out.println("We got an error: " + t);
            int remaining = this.shutdownNow().size();
            System.out.println(remaining + " Runnables left in the queue");
        }
    }
}

MyRunnable.java

package org.codechimp.threadpool;

import org.apache.commons.lang.math.RandomUtils;

public class MyRunnable implements Runnable {
    private int runnableNumber;
    private int counter = 0;

    public MyRunnable(int number) {
        this.runnableNumber = number;
    }

    /**
     * Simple runnable that generates an OutOfMemoryError after the 1000th loop
     */
    public void run() {
        while (counter < 1000) {
            counter++;
            if (counter % 100 == 0) {
                System.out.println("\tRunnable " + this.runnableNumber + " reached " + this.counter + ".");
            }

            if (this.runnableNumber == 15 && this.counter % 200 == 0) {
                throw new OutOfMemoryError("This is a test!");
            }

            int wait = RandomUtils.nextInt(100);
            if (wait > 0) {
                try {
                    //System.out.println("\tRunnable " + this.runnableNumber + " waiting " + wait + ".");
                    Thread.sleep(wait);
                } catch (InterruptedException e) {
                    throw new RuntimeException("Thread.sleep() failed", e);
                }
            }
        }
    }
}

This is a super-simple example that will create 10k of MyRunnables into the MyThreadPoolExectuor, printing out some status messages as the counters increase. The 16th runnable (number 15, counts from 0) will throw an OutOfMemoryError on the 200th increment. MyThreadPoolExecutor's afterExecute() will print a message if it gets a Throwable. When I run it under Java 6 and Java 7, it never prints this message.

How do we make the app bail on ALL Throwables? We really want to just terminate things at that point.

Update/Edit:

I am updating this as there seems to be some confusion as to what I am asking. I know the error gets printed out. The problem isn't that ThreadPoolExecutor isn't printing OutOfMemoryError, the problem is, as stated in the title and in the question I ask in the end, that the afterExecute() is not being called for Errors. Since OutOfMemoryError is a sub-class of Error, that means when one occurs I have NO WAY to stop the code.

Again, please read what the code is trying to do. It is most certainly trying to "handle" the error. It is in fact trying to stop the ThreadPoolExecutor by calling shutdownNow() on it. But, since the Error being generated is being suppressed somehow, that bit of code is not being executed. As a result, the application simply keeps chugging along, ignoring the fact that it's spewing OOME all over the place.

Again, the question:

How do I detect a Runnable has recieved an Error (OutOfMemoryError or other) and terminate the ThreadPoolExecutor so the app will simply stop in it's tracks?

CodeChimp
  • 8,016
  • 5
  • 41
  • 79
  • I did run your code in Java jdk1.7.0_40 and got this error message > We got an error: java.lang.OutOfMemoryError: This is a test! – Maas Sep 05 '14 at 14:26
  • http://stackoverflow.com/questions/511013/how-to-handle-outofmemoryerror-in-java, http://stackoverflow.com/questions/37335/how-to-deal-with-java-lang-outofmemoryerror-java-heap-space-error-64mb-heap. The bottom line: you should not handle OutOfMemoryError, you should prevent it from happening – jny Sep 05 '14 at 14:31
  • Works for me .. i see the error. – Simone Gianni Sep 05 '14 at 14:42
  • I know the error prints. The problem is that the `afterExecute()` does not get called on Errors. It should be. Error is Throwable, and according to the javadoc, `afterExecute()` takes the Runnable and any Throwable produced while running. It does not state anywhere that Errors are excluded, nor should they be since they are a sub-class of Throwable. The code, if you read it, attempts to terminate when it gets any Throwable, so in essences I am trying to do exactly what @jny suggest: handle the error, but since I have no way to know it happened, how can I do that? – CodeChimp Sep 05 '14 at 17:58

2 Answers2

0

Let me simply explain through code, If you look at the runWorker() implementation, it is found that the error is still sent in afterExecute(). So there is no way you will skip the errors if you use afterExecute hook. Please refer https://stackoverflow.com/a/50480190/5620851.

final void runWorker(Worker arg0) {
    Thread arg1 = Thread.currentThread();
    Runnable arg2 = arg0.firstTask;
    arg0.firstTask = null;
    arg0.unlock();
    boolean arg3 = true;

    try {
        while (arg2 != null || (arg2 = this.getTask()) != null) {
            arg0.lock();
            ..
            try {
                this.beforeExecute(arg1, arg2);
                Object arg4 = null;

                try {
                    arg2.run();
                } catch (RuntimeException arg27) {
                    arg4 = arg27;
                    throw arg27;
                } catch (Error arg28) {
                    arg4 = arg28;
                    throw arg28;
                } catch (Throwable arg29) {
                    arg4 = arg29;
                    throw new Error(arg29);
                } finally {
                    this.afterExecute(arg2, (Throwable) arg4);
                }
            } finally {
                arg2 = null;
                ++arg0.completedTasks;
                arg0.unlock();
            }
        }

        arg3 = false;
    } finally {
        this.processWorkerExit(arg0, arg3);
    }

}
hi.nitish
  • 2,732
  • 2
  • 14
  • 21
  • TBH, this was asked 4yrs ago, so I can't remember why I was trying to do that, but it looks like, from the description, that the error was NOT being sent to the `afterExecute`, which sort of contradicts what I think the code you are posting is doing. I specifically mentioned Java 6 and 7, so maybe it was fixed/changed in Java 8? – CodeChimp May 23 '18 at 11:45
  • yes, you may be correct, I just left the post since the subject of our post looks more appropriate. – hi.nitish May 24 '18 at 09:44
-1

I did run your code and here are my findings. Error in one task is not blocker for other. In below output, error is thrown after 16th task but program does not terminate and other tasks are successfully executed. Only after 1000th task is executed, afterExecute method is called. You are probably expecting afterExecute to be called after each task. But that is not the case. Also looks like afterExecute method is not getting throwable at task level but rather at threadpool level.

I had modified afterExecute just to confirm that its getting called

 @Override
    protected void afterExecute(Runnable r, Throwable t) {
        if (t != null) {
            System.out.println("We got an error: " + t);
            int remaining = this.shutdownNow().size();
            System.out.println(remaining + " Runnables left in the queue");
        }else{
            System.out.println("t is null");
            if(r!=null){
                System.out.println(r.toString() +" after execute");
            }else{
                System.out.println("r is null");
            }
        }
    }

Snippet of console output with OOM error:

Queued 0 Runnables
Queued 100 Runnables
Queued 200 Runnables
Queued 300 Runnables
Queued 400 Runnables
Queued 500 Runnables
Queued 600 Runnables
Queued 700 Runnables
Queued 800 Runnables
Queued 900 Runnables
Queued 1000 Runnables
Queued 1100 Runnables
Queued 1200 Runnables
Queued 1300 Runnables
Queued 1400 Runnables
Queued 1500 Runnables
Queued 1600 Runnables
Queued 1700 Runnables
Queued 1800 Runnables
Queued 1900 Runnables
Queued 2000 Runnables
Queued 2100 Runnables
Queued 2200 Runnables
Queued 2300 Runnables
Queued 2400 Runnables
Queued 2500 Runnables
Queued 2600 Runnables
Queued 2700 Runnables
Queued 2800 Runnables
Queued 2900 Runnables
Queued 3000 Runnables
Queued 3100 Runnables
Queued 3200 Runnables
Queued 3300 Runnables
Queued 3400 Runnables
Queued 3500 Runnables
Queued 3600 Runnables
Queued 3700 Runnables
Queued 3800 Runnables
Queued 3900 Runnables
Queued 4000 Runnables
Queued 4100 Runnables
Queued 4200 Runnables
Queued 4300 Runnables
Queued 4400 Runnables
Queued 4500 Runnables
Queued 4600 Runnables
Queued 4700 Runnables
Queued 4800 Runnables
Queued 4900 Runnables
Queued 5000 Runnables
Queued 5100 Runnables
Queued 5200 Runnables
Queued 5300 Runnables
Queued 5400 Runnables
Queued 5500 Runnables
Queued 5600 Runnables
Queued 5700 Runnables
Queued 5800 Runnables
Queued 5900 Runnables
Queued 6000 Runnables
Queued 6100 Runnables
Queued 6200 Runnables
Queued 6300 Runnables
Queued 6400 Runnables
Queued 6500 Runnables
Queued 6600 Runnables
Queued 6700 Runnables
Queued 6800 Runnables
Queued 6900 Runnables
Queued 7000 Runnables
Queued 7100 Runnables
Queued 7200 Runnables
Queued 7300 Runnables
Queued 7400 Runnables
Queued 7500 Runnables
Queued 7600 Runnables
Queued 7700 Runnables
Queued 7800 Runnables
Queued 7900 Runnables
Queued 8000 Runnables
Queued 8100 Runnables
Queued 8200 Runnables
Queued 8300 Runnables
Queued 8400 Runnables
Queued 8500 Runnables
Queued 8600 Runnables
Queued 8700 Runnables
Queued 8800 Runnables
Queued 8900 Runnables
Queued 9000 Runnables
Queued 9100 Runnables
Queued 9200 Runnables
Queued 9300 Runnables
Queued 9400 Runnables
Queued 9500 Runnables
Queued 9600 Runnables
Queued 9700 Runnables
Queued 9800 Runnables
Queued 9900 Runnables
Done queing the Runnables.
9990 Runnables in the queue.
9990 Runnables in the queue.
9990 Runnables in the queue.
9990 Runnables in the queue.
9990 Runnables in the queue.
    Runnable 0 reached 100.
    Runnable 7 reached 100.
    Runnable 8 reached 100.
    Runnable 9 reached 100.
    Runnable 5 reached 100.
    Runnable 1 reached 100.
    Runnable 6 reached 100.
    Runnable 4 reached 100.
    Runnable 2 reached 100.
9990 Runnables in the queue.
    Runnable 3 reached 100.
9990 Runnables in the queue.
9990 Runnables in the queue.
9990 Runnables in the queue.
9990 Runnables in the queue.
    Runnable 0 reached 200.
    Runnable 7 reached 200.
    Runnable 5 reached 200.
    Runnable 9 reached 200.
    Runnable 1 reached 200.
    Runnable 6 reached 200.
    Runnable 3 reached 200.
    Runnable 4 reached 200.
    Runnable 8 reached 200.
9990 Runnables in the queue.
    Runnable 2 reached 200.
9990 Runnables in the queue.
9990 Runnables in the queue.
9990 Runnables in the queue.
9990 Runnables in the queue.
    Runnable 7 reached 300.
    Runnable 1 reached 300.
    Runnable 0 reached 300.
    Runnable 5 reached 300.
    Runnable 4 reached 300.
    Runnable 3 reached 300.
    Runnable 8 reached 300.
    Runnable 6 reached 300.
9990 Runnables in the queue.
    Runnable 9 reached 300.
    Runnable 2 reached 300.
9990 Runnables in the queue.
9990 Runnables in the queue.
9990 Runnables in the queue.
9990 Runnables in the queue.
    Runnable 7 reached 400.
    Runnable 1 reached 400.
    Runnable 0 reached 400.
    Runnable 3 reached 400.
    Runnable 5 reached 400.
    Runnable 8 reached 400.
    Runnable 9 reached 400.
9990 Runnables in the queue.
    Runnable 6 reached 400.
    Runnable 4 reached 400.
    Runnable 2 reached 400.
9990 Runnables in the queue.
9990 Runnables in the queue.
9990 Runnables in the queue.
    Runnable 1 reached 500.
9990 Runnables in the queue.
    Runnable 7 reached 500.
    Runnable 0 reached 500.
    Runnable 3 reached 500.
    Runnable 6 reached 500.
9990 Runnables in the queue.
    Runnable 5 reached 500.
    Runnable 4 reached 500.
    Runnable 8 reached 500.
    Runnable 9 reached 500.
    Runnable 2 reached 500.
9990 Runnables in the queue.
9990 Runnables in the queue.
9990 Runnables in the queue.
    Runnable 1 reached 600.
9990 Runnables in the queue.
    Runnable 7 reached 600.
    Runnable 3 reached 600.
    Runnable 8 reached 600.
    Runnable 5 reached 600.
    Runnable 0 reached 600.
9990 Runnables in the queue.
    Runnable 4 reached 600.
    Runnable 2 reached 600.
    Runnable 6 reached 600.
    Runnable 9 reached 600.
9990 Runnables in the queue.
9990 Runnables in the queue.
9990 Runnables in the queue.
9990 Runnables in the queue.
    Runnable 1 reached 700.
    Runnable 8 reached 700.
    Runnable 7 reached 700.
    Runnable 5 reached 700.
    Runnable 3 reached 700.
    Runnable 2 reached 700.
9990 Runnables in the queue.
    Runnable 9 reached 700.
    Runnable 4 reached 700.
    Runnable 6 reached 700.
    Runnable 0 reached 700.
9990 Runnables in the queue.
9990 Runnables in the queue.
9990 Runnables in the queue.
    Runnable 1 reached 800.
9990 Runnables in the queue.
    Runnable 7 reached 800.
    Runnable 3 reached 800.
    Runnable 8 reached 800.
    Runnable 5 reached 800.
    Runnable 2 reached 800.
9990 Runnables in the queue.
    Runnable 4 reached 800.
    Runnable 9 reached 800.
    Runnable 0 reached 800.
    Runnable 6 reached 800.
9990 Runnables in the queue.
9990 Runnables in the queue.
9990 Runnables in the queue.
    Runnable 1 reached 900.
9990 Runnables in the queue.
    Runnable 7 reached 900.
    Runnable 8 reached 900.
    Runnable 5 reached 900.
    Runnable 9 reached 900.
    Runnable 3 reached 900.
    Runnable 2 reached 900.
9990 Runnables in the queue.
    Runnable 4 reached 900.
    Runnable 0 reached 900.
    Runnable 6 reached 900.
9990 Runnables in the queue.
9990 Runnables in the queue.
    Runnable 1 reached 1000.
t is null
threadTest.MyRunnable@7d29f3b5 after execute
9990 Runnables in the queue.
9989 Runnables in the queue.
    Runnable 7 reached 1000.
t is null
threadTest.MyRunnable@4d3f3045 after execute
    Runnable 8 reached 1000.
    Runnable 5 reached 1000.
t is null
threadTest.MyRunnable@6f7a29a1 after execute
    Runnable 3 reached 1000.
t is null
threadTest.MyRunnable@3d434234 after execute
t is null
threadTest.MyRunnable@aaf8358 after execute
9985 Runnables in the queue.
    Runnable 4 reached 1000.
    Runnable 2 reached 1000.
t is null
threadTest.MyRunnable@8d80be3 after execute
t is null
threadTest.MyRunnable@1ff4689e after execute
    Runnable 9 reached 1000.
t is null
threadTest.MyRunnable@67006d75 after execute
    Runnable 6 reached 1000.
t is null
threadTest.MyRunnable@4d125127 after execute
9981 Runnables in the queue.
    Runnable 0 reached 1000.
t is null
threadTest.MyRunnable@33db4f6f after execute
9980 Runnables in the queue.
    Runnable 10 reached 100.
9980 Runnables in the queue.
9980 Runnables in the queue.
    Runnable 11 reached 100.
    Runnable 12 reached 100.
    Runnable 14 reached 100.
    Runnable 16 reached 100.
9980 Runnables in the queue.
    Runnable 18 reached 100.
    Runnable 13 reached 100.
    Runnable 17 reached 100.
    Runnable 15 reached 100.
    Runnable 19 reached 100.
9980 Runnables in the queue.
9980 Runnables in the queue.
    Runnable 10 reached 200.
9980 Runnables in the queue.
9980 Runnables in the queue.
    Runnable 11 reached 200.
    Runnable 13 reached 200.
    Runnable 14 reached 200.
    Runnable 12 reached 200.
9980 Runnables in the queue.
    Runnable 16 reached 200.
    Runnable 18 reached 200.
    Runnable 15 reached 200.
Exception in thread "pool-1-thread-3" java.lang.OutOfMemoryError: This is a test!
    at threadTest.MyRunnable.run(MyRunnable.java:25)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:680)
    Runnable 17 reached 200.
    Runnable 19 reached 200.
9980 Runnables in the queue.
9980 Runnables in the queue.
    Runnable 10 reached 300.
9980 Runnables in the queue.
9980 Runnables in the queue.
    Runnable 11 reached 300.
    Runnable 12 reached 300.
    Runnable 13 reached 300.
9980 Runnables in the queue.
    Runnable 14 reached 300.
    Runnable 18 reached 300.
    Runnable 17 reached 300.
    Runnable 19 reached 300.
    Runnable 16 reached 300.
9980 Runnables in the queue.
9980 Runnables in the queue.
    Runnable 10 reached 400.
9980 Runnables in the queue.
9980 Runnables in the queue.
    Runnable 11 reached 400.
    Runnable 12 reached 400.
    Runnable 13 reached 400.
9980 Runnables in the queue.
    Runnable 18 reached 400.
    Runnable 14 reached 400.
    Runnable 17 reached 400.
9980 Runnables in the queue.
    Runnable 16 reached 400.
    Runnable 19 reached 400.
    Runnable 10 reached 500.
9980 Runnables in the queue.
9980 Runnables in the queue.
9980 Runnables in the queue.
    Runnable 13 reached 500.
    Runnable 12 reached 500.
    Runnable 11 reached 500.
9980 Runnables in the queue.
    Runnable 14 reached 500.
    Runnable 17 reached 500.
    Runnable 18 reached 500.
    Runnable 16 reached 500.
9980 Runnables in the queue.
    Runnable 19 reached 500.
    Runnable 10 reached 600.
9980 Runnables in the queue.
9980 Runnables in the queue.
9980 Runnables in the queue.
    Runnable 13 reached 600.
9980 Runnables in the queue.
    Runnable 12 reached 600.
    Runnable 14 reached 600.
    Runnable 11 reached 600.
    Runnable 18 reached 600.
    Runnable 16 reached 600.
    Runnable 17 reached 600.
9980 Runnables in the queue.
    Runnable 19 reached 600.
    Runnable 10 reached 700.
9980 Runnables in the queue.
9980 Runnables in the queue.
9980 Runnables in the queue.
    Runnable 13 reached 700.
9980 Runnables in the queue.
    Runnable 11 reached 700.
    Runnable 14 reached 700.
    Runnable 18 reached 700.
    Runnable 16 reached 700.
    Runnable 12 reached 700.
9980 Runnables in the queue.
    Runnable 17 reached 700.
    Runnable 10 reached 800.
    Runnable 19 reached 700.
9980 Runnables in the queue.
9980 Runnables in the queue.
9980 Runnables in the queue.
    Runnable 13 reached 800.
9980 Runnables in the queue.
    Runnable 18 reached 800.
    Runnable 14 reached 800.
    Runnable 12 reached 800.
    Runnable 16 reached 800.
    Runnable 11 reached 800.
9980 Runnables in the queue.
    Runnable 17 reached 800.
    Runnable 10 reached 900.
9980 Runnables in the queue.
    Runnable 19 reached 800.
9980 Runnables in the queue.
9980 Runnables in the queue.
    Runnable 13 reached 900.
    Runnable 18 reached 900.
9980 Runnables in the queue.
    Runnable 14 reached 900.
    Runnable 12 reached 900.
    Runnable 16 reached 900.
    Runnable 11 reached 900.
9980 Runnables in the queue.
    Runnable 10 reached 1000.
t is null
threadTest.MyRunnable@10b61fd1 after execute
    Runnable 17 reached 900.
    Runnable 19 reached 900.
9979 Runnables in the queue.
9979 Runnables in the queue.
9979 Runnables in the queue.
    Runnable 13 reached 1000.
    Runnable 18 reached 1000.
t is null
threadTest.MyRunnable@24e2dae9 after execute
t is null
threadTest.MyRunnable@299209ea after execute
9977 Runnables in the queue.
    Runnable 14 reached 1000.
t is null
threadTest.MyRunnable@32c8f6f8 after execute
    Runnable 11 reached 1000.
t is null
threadTest.MyRunnable@27ce2dd4 after execute
    Runnable 16 reached 1000.
t is null
threadTest.MyRunnable@5122cdb6 after execute
    Runnable 12 reached 1000.
t is null
threadTest.MyRunnable@43ef9157 after execute
9973 Runnables in the queue.
    Runnable 20 reached 100.
    Runnable 17 reached 1000.
t is null
threadTest.MyRunnable@252f0999 after execute
    Runnable 19 reached 1000.
t is null
threadTest.MyRunnable@331f2ee1 after execute
9971 Runnables in the queue.
9971 Runnables in the queue.
9971 Runnables in the queue.
    Runnable 21 reached 100.
    Runnable 22 reached 100.
9971 Runnables in the queue.
    Runnable 26 reached 100.
    Runnable 23 reached 100.
    Runnable 24 reached 100.
9971 Runnables in the queue.
    Runnable 25 reached 100.
    Runnable 28 reached 100.
    Runnable 20 reached 200.
    Runnable 27 reached 100.
9971 Runnables in the queue.
9971 Runnables in the queue.
9971 Runnables in the queue.
9971 Runnables in the queue.
    Runnable 21 reached 200.
    Runnable 24 reached 200.
    Runnable 22 reached 200.
9971 Runnables in the queue.
    Runnable 26 reached 200.
    Runnable 20 reached 300.
    Runnable 23 reached 200.
    Runnable 25 reached 200.
    Runnable 27 reached 200.
    Runnable 28 reached 200.
9971 Runnables in the queue.
9971 Runnables in the queue.
9971 Runnables in the queue.
9971 Runnables in the queue.
    Runnable 24 reached 300.
9971 Runnables in the queue.
    Runnable 22 reached 300.
    Runnable 21 reached 300.
    Runnable 25 reached 300.
    Runnable 20 reached 400.
    Runnable 26 reached 300.
    Runnable 23 reached 300.
    Runnable 27 reached 300.
    Runnable 28 reached 300.
9971 Runnables in the queue.
9971 Runnables in the queue.
9971 Runnables in the queue.
9971 Runnables in the queue.
    Runnable 24 reached 400.
    Runnable 22 reached 400.
9971 Runnables in the queue.
    Runnable 21 reached 400.
    Runnable 26 reached 400.
    Runnable 20 reached 500.
    Runnable 23 reached 400.
    Runnable 25 reached 400.
    Runnable 27 reached 400.
9971 Runnables in the queue.
    Runnable 28 reached 400.
9971 Runnables in the queue.
9971 Runnables in the queue.
9971 Runnables in the queue.
    Runnable 24 reached 500.
    Runnable 22 reached 500.
    Runnable 21 reached 500.
9971 Runnables in the queue.
    Runnable 20 reached 600.
    Runnable 25 reached 500.
    Runnable 26 reached 500.
    Runnable 23 reached 500.
    Runnable 27 reached 500.
9971 Runnables in the queue.
    Runnable 28 reached 500.
9971 Runnables in the queue.
9971 Runnables in the queue.
9971 Runnables in the queue.
    Runnable 25 reached 600.
    Runnable 24 reached 600.
    Runnable 22 reached 600.
    Runnable 20 reached 700.
9971 Runnables in the queue.
    Runnable 21 reached 600.
    Runnable 26 reached 600.
    Runnable 23 reached 600.
    Runnable 27 reached 600.
9971 Runnables in the queue.
    Runnable 28 reached 600.
9971 Runnables in the queue.
9971 Runnables in the queue.
    Runnable 25 reached 700.
    Runnable 22 reached 700.
9971 Runnables in the queue.
    Runnable 21 reached 700.
    Runnable 24 reached 700.
9971 Runnables in the queue.
    Runnable 23 reached 700.
    Runnable 20 reached 800.
    Runnable 27 reached 700.
    Runnable 26 reached 700.
    Runnable 28 reached 700.
9971 Runnables in the queue.
9971 Runnables in the queue.
9971 Runnables in the queue.
    Runnable 25 reached 800.
    Runnable 22 reached 800.
9971 Runnables in the queue.
    Runnable 24 reached 800.
    Runnable 21 reached 800.
9971 Runnables in the queue.
    Runnable 23 reached 800.
    Runnable 20 reached 900.
    Runnable 26 reached 800.
    Runnable 27 reached 800.
9971 Runnables in the queue.
    Runnable 28 reached 800.
9971 Runnables in the queue.
9971 Runnables in the queue.
    Runnable 25 reached 900.
    Runnable 22 reached 900.
9971 Runnables in the queue.
    Runnable 24 reached 900.
    Runnable 21 reached 900.
    Runnable 20 reached 1000.
9971 Runnables in the queue.
t is null
threadTest.MyRunnable@443ecfff after execute
    Runnable 23 reached 900.
    Runnable 27 reached 900.
9970 Runnables in the queue.
    Runnable 26 reached 900.
    Runnable 28 reached 900.
9970 Runnables in the queue.
9970 Runnables in the queue.
    Runnable 22 reached 1000.
t is null
threadTest.MyRunnable@77c99159 after execute
9969 Runnables in the queue.
    Runnable 24 reached 1000.
t is null
threadTest.MyRunnable@5265a77f after execute
    Runnable 25 reached 1000.
t is null
threadTest.MyRunnable@fd7ad1c after execute
    Runnable 21 reached 1000.
t is null
threadTest.MyRunnable@18a61164 after execute
9966 Runnables in the queue.
    Runnable 29 reached 100.
    Runnable 23 reached 1000.
t is null
threadTest.MyRunnable@3ebfc8e0 after execute
9965 Runnables in the queue.
    Runnable 26 reached 1000.
t is null
threadTest.MyRunnable@211d0a4f after execute
    Runnable 27 reached 1000.
t is null
threadTest.MyRunnable@798fd984 after execute
    Runnable 28 reached 1000.
t is null
threadTest.MyRunnable@5311a775 after execute
9962 Runnables in the queue.
9962 Runnables in the queue.
    Runnable 30 reached 100.
    Runnable 32 reached 100.
9962 Runnables in the queue.
    Runnable 31 reached 100.
    Runnable 33 reached 100.
9962 Runnables in the queue.
    Runnable 34 reached 100.
    Runnable 29 reached 200.
    Runnable 35 reached 100.
9962 Runnables in the queue.
    Runnable 37 reached 100.
    Runnable 36 reached 100.
9962 Runnables in the queue.
9962 Runnables in the queue.
    Runnable 30 reached 200.
    Runnable 32 reached 200.
9962 Runnables in the queue.
    Runnable 31 reached 200.
9962 Runnables in the queue.
    Runnable 33 reached 200.
    Runnable 29 reached 300.
    Runnable 34 reached 200.
9962 Runnables in the queue.
    Runnable 35 reached 200.
    Runnable 37 reached 200.
    Runnable 36 reached 200.
9962 Runnables in the queue.
9962 Runnables in the queue.
    Runnable 30 reached 300.
    Runnable 32 reached 300.
9962 Runnables in the queue.
    Runnable 31 reached 300.
9962 Runnables in the queue.
    Runnable 33 reached 300.
    Runnable 29 reached 400.
9962 Runnables in the queue.
    Runnable 34 reached 300.
    Runnable 35 reached 300.
    Runnable 36 reached 300.
    Runnable 37 reached 300.
9962 Runnables in the queue.
9962 Runnables in the queue.
    Runnable 32 reached 400.
    Runnable 30 reached 400.
9962 Runnables in the queue.
9962 Runnables in the queue.
    Runnable 31 reached 400.
    Runnable 33 reached 400.
9962 Runnables in the queue.
    Runnable 29 reached 500.
    Runnable 34 reached 400.
    Runnable 35 reached 400.
    Runnable 37 reached 400.
9962 Runnables in the queue.
    Runnable 36 reached 400.
9962 Runnables in the queue.
    Runnable 30 reached 500.
    Runnable 32 reached 500.
9962 Runnables in the queue.
9962 Runnables in the queue.
    Runnable 33 reached 500.
    Runnable 31 reached 500.
    Runnable 34 reached 500.
    Runnable 29 reached 600.
9962 Runnables in the queue.
    Runnable 37 reached 500.
    Runnable 35 reached 500.
9962 Runnables in the queue.
    Runnable 36 reached 500.
9962 Runnables in the queue.
    Runnable 30 reached 600.
    Runnable 32 reached 600.
9962 Runnables in the queue.
9962 Runnables in the queue.
    Runnable 33 reached 600.
    Runnable 31 reached 600.
    Runnable 29 reached 700.
9962 Runnables in the queue.
    Runnable 34 reached 600.
9962 Runnables in the queue.
    Runnable 37 reached 600.
    Runnable 35 reached 600.
    Runnable 36 reached 600.
    Runnable 30 reached 700.
9962 Runnables in the queue.
    Runnable 32 reached 700.
9962 Runnables in the queue.
9962 Runnables in the queue.
    Runnable 33 reached 700.
    Runnable 31 reached 700.
9962 Runnables in the queue.
    Runnable 34 reached 700.
    Runnable 29 reached 800.
    Runnable 37 reached 700.
    Runnable 35 reached 700.
9962 Runnables in the queue.
    Runnable 30 reached 800.
    Runnable 36 reached 700.
9962 Runnables in the queue.
    Runnable 32 reached 800.
9962 Runnables in the queue.
9962 Runnables in the queue.
    Runnable 33 reached 800.
    Runnable 31 reached 800.
    Runnable 29 reached 900.
    Runnable 34 reached 800.
9962 Runnables in the queue.
    Runnable 35 reached 800.
    Runnable 37 reached 800.
9962 Runnables in the queue.
    Runnable 30 reached 900.
9962 Runnables in the queue.
    Runnable 36 reached 800.
    Runnable 32 reached 900.
9962 Runnables in the queue.
9962 Runnables in the queue.
    Runnable 33 reached 900.
    Runnable 34 reached 900.
    Runnable 29 reached 1000.
    Runnable 31 reached 900.
9962 Runnables in the queue.
t is null
threadTest.MyRunnable@2c091cee after execute
    Runnable 35 reached 900.
    Runnable 37 reached 900.
9961 Runnables in the queue.
    Runnable 30 reached 1000.
t is null
threadTest.MyRunnable@a4a63d8 after execute
    Runnable 36 reached 900.
9960 Runnables in the queue.
    Runnable 32 reached 1000.
t is null
threadTest.MyRunnable@19e0ff2f after execute
9959 Runnables in the queue.
9959 Runnables in the queue.
    Runnable 33 reached 1000.
t is null
threadTest.MyRunnable@29173ef after execute
    Runnable 38 reached 100.
    Runnable 34 reached 1000.
9958 Runnables in the queue.
t is null
threadTest.MyRunnable@1b52513a after execute
    Runnable 31 reached 1000.
t is null
threadTest.MyRunnable@3952c4d9 after execute
    Runnable 37 reached 1000.
t is null
threadTest.MyRunnable@68f99ff5 after execute
    Runnable 35 reached 1000.
t is null
threadTest.MyRunnable@5c74c3aa after execute
9954 Runnables in the queue.
    Runnable 39 reached 100.
    Runnable 36 reached 1000.
t is null
threadTest.MyRunnable@75d9fd51 after execute
9953 Runnables in the queue.
    Runnable 40 reached 100.
9953 Runnables in the queue.
9953 Runnables in the queue.
    Runnable 42 reached 100.
    Runnable 41 reached 100.
9953 Runnables in the queue.
    Runnable 38 reached 200.
    Runnable 43 reached 100.
    Runnable 44 reached 100.
9953 Runnables in the queue.
    Runnable 45 reached 100.
    Runnable 46 reached 100.
9953 Runnables in the queue.
    Runnable 39 reached 200.
    Runnable 40 reached 200.
9953 Runnables in the queue.
9953 Runnables in the queue.
    Runnable 42 reached 200.
    Runnable 41 reached 200.
9953 Runnables in the queue.
    Runnable 38 reached 300.
    Runnable 44 reached 200.
    Runnable 43 reached 200.
9953 Runnables in the queue.
    Runnable 45 reached 200.
    Runnable 46 reached 200.
9953 Runnables in the queue.
    Runnable 39 reached 300.
    Runnable 40 reached 300.
9953 Runnables in the queue.
9953 Runnables in the queue.
    Runnable 41 reached 300.
    Runnable 42 reached 300.
9953 Runnables in the queue.
    Runnable 38 reached 400.
    Runnable 44 reached 300.
    Runnable 43 reached 300.
    Runnable 45 reached 300.
9953 Runnables in the queue.
    Runnable 46 reached 300.
9953 Runnables in the queue.
    Runnable 40 reached 400.
9953 Runnables in the queue.
    Runnable 39 reached 400.
9953 Runnables in the queue.
    Runnable 41 reached 400.
9953 Runnables in the queue.
    Runnable 42 reached 400.
    Runnable 38 reached 500.
    Runnable 44 reached 400.
    Runnable 43 reached 400.
    Runnable 45 reached 400.
9953 Runnables in the queue.
    Runnable 46 reached 400.
9953 Runnables in the queue.
    Runnable 40 reached 500.
9953 Runnables in the queue.
    Runnable 39 reached 500.
    Runnable 41 reached 500.
9953 Runnables in the queue.
    Runnable 42 reached 500.
9953 Runnables in the queue.
    Runnable 43 reached 500.
    Runnable 38 reached 600.
9953 Runnables in the queue.
    Runnable 45 reached 500.
    Runnable 44 reached 500.
    Runnable 46 reached 500.
9953 Runnables in the queue.
    Runnable 40 reached 600.
    Runnable 39 reached 600.
9953 Runnables in the queue.
    Runnable 41 reached 600.
9953 Runnables in the queue.
    Runnable 42 reached 600.
9953 Runnables in the queue.
    Runnable 43 reached 600.
    Runnable 44 reached 600.
    Runnable 38 reached 700.
9953 Runnables in the queue.
    Runnable 45 reached 600.
9953 Runnables in the queue.
    Runnable 40 reached 700.
    Runnable 46 reached 600.
9953 Runnables in the queue.
    Runnable 39 reached 700.
    Runnable 41 reached 700.
9953 Runnables in the queue.
    Runnable 42 reached 700.
9953 Runnables in the queue.
    Runnable 43 reached 700.
    Runnable 38 reached 800.
9953 Runnables in the queue.
    Runnable 44 reached 700.
    Runnable 45 reached 700.
9953 Runnables in the queue.
    Runnable 46 reached 700.
    Runnable 40 reached 800.
    Runnable 39 reached 800.
9953 Runnables in the queue.
9953 Runnables in the queue.
    Runnable 41 reached 800.
    Runnable 42 reached 800.
9953 Runnables in the queue.
    Runnable 43 reached 800.
    Runnable 44 reached 800.
    Runnable 38 reached 900.
9953 Runnables in the queue.
    Runnable 45 reached 800.
9953 Runnables in the queue.
    Runnable 46 reached 800.
    Runnable 40 reached 900.
9953 Runnables in the queue.
    Runnable 39 reached 900.

UPDATE: This is what i got from official documentation at http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html which confirms observed behaviour

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:

Pranalee
  • 3,389
  • 3
  • 22
  • 36
  • 1
    I actually read this, but in this case I am not wrapping it in a `FutureTask`. Besides, an OutOfMemoryError is not a computational error, is it? A "computational" error is more like NumberFormatException or NullPointerException, which ironically gets caught as I expect by the sample code. In fact, if you read the source code of `ThreadPoolExecutor.runWorker()` (around line 1098), the call to `afterExecute()` is in a `finally` and thus **should** be called after all each iteration. – CodeChimp Sep 08 '14 at 11:34