JDK-6450211 : ThreadPoolExecutor.afterExecute sees RuntimeExceptions, but not Errors
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util.concurrent
  • Affected Version: 6
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2006-07-19
  • Updated: 2011-05-18
  • Resolved: 2011-05-18
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7
7 b08Fixed
Related Reports
Relates :  
Relates :  
Description
ThreadPoolExecutor.afterExecute takes a Throwable, and is specified to be
passed any RuntimeException or Error thrown by the task.

However the code only handles RuntimeException, causing the results below to 
be different for Error.

------------------
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;

public class Bug6 {
    private static final AtomicInteger uncaughtExceptions
	= new AtomicInteger(0);

    private static final Thread.UncaughtExceptionHandler handler
	= new Thread.UncaughtExceptionHandler() {
		public void uncaughtException(Thread t, Throwable e) {
		    uncaughtExceptions.getAndIncrement(); }};

    static void report(String label, ThreadPoolExecutor tpe) {
	System.out.printf("%10s: active=%d, submitted=%d, completed=%d%n",
			  label,
			  Thread.activeCount() - 1,
			  tpe.getTaskCount(),
			  tpe.getCompletedTaskCount());
    }

    static final Map<Class<?>, Integer> counts
	= new HashMap<Class<?>, Integer>();

    static class MyExecutor extends ThreadPoolExecutor {
	MyExecutor() {
	    super(10, 30, 1L, TimeUnit.HOURS,
		  new LinkedBlockingQueue<Runnable>());
	}

	@Override protected void afterExecute(Runnable r, Throwable t) {
	    if (t != null) {
		Class<?> klazz = t.getClass();
		Integer x = counts.get(klazz);
		counts.put(klazz, x == null ? 1 : x + 1);
	    }
	}
    }

    public static void main(String[] args) throws Throwable {
	Thread.setDefaultUncaughtExceptionHandler(handler);

	final int count = 8;
	final CyclicBarrier barrier = new CyclicBarrier(count + 1);
	ThreadPoolExecutor tpe = new MyExecutor();

	for (int i = 0; i < 5; i++) {
	    tpe.execute(new Runnable() {
		    public void run() {
			throw new RuntimeException();
		    }});
	    tpe.execute(new Runnable() {
		    public void run() {
			throw new Error();
		    }});
	}

	tpe.shutdown();
	tpe.awaitTermination(1L, TimeUnit.HOURS);

	System.out.printf("RuntimeException => %d%n",
			  counts.get(RuntimeException.class));
	System.out.printf("Error => %d%n",
			  counts.get(Error.class));
    }
}
------------------
$ jver 6 jr Bug6
==> javac -source 1.6 -Xlint:all Bug6.java
==> java -esa -ea Bug6
RuntimeException => 5
Error => null

Comments
EVALUATION Submitter is correct.
19-07-2006