JDK-6689310 : Backmerge of 6576792 ThreadPoolExecutor#setCorePoolSize interrupts client code
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util.concurrent
  • Affected Version: 7
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: solaris_10
  • CPU: sparc
  • Submitted: 2008-04-16
  • Updated: 2011-02-16
  • Resolved: 2008-07-16
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
$ java -version
java version "1.6.0_03"
Java(TM) SE Runtime Environment (build 1.6.0_03-b05)
Java HotSpot(TM) Server VM (build 1.6.0_03-b05, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
any os

$ uname -a
SunOS t1000 5.10 Generic_127111-09 sun4v sparc SUNW,Sun-Fire-T1000

A DESCRIPTION OF THE PROBLEM :
Decrease of ThreadPoolExecutor core pool size interrupts running tasks. This is described in http://bugs.sun.com/view_bug.do?bug_id=6576792 as regression which is not correct. The regression is that with the fixes incorporated in JDK 7 build 08 this bug will occur ALWAYS, before the fix the bug only occured OFTEN. A test case to prove this is provided below.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Submit a task to a ThreadPoolExecutor instance and call "setCorePoolSize" in  task code.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The task is NOT interrupted.
ACTUAL -
The task IS interrupted.

REPRODUCIBILITY :
This bug can be reproduced often.

---------- BEGIN SOURCE ----------
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ExecutionException;


public class Test {


	public void test() throws InterruptedException, ExecutionException {
		// thread pool executor with 3 slots; will be decreased to 1 to provoke thread interruption
			final ThreadPoolExecutor executor = new ThreadPoolExecutor(
					3, 3,	// it's important to use a value of 3 because ThreadPoolExecutor.setMaximumPoolSize() only _tries_ "oldMaxCore - newMaxCore" times
					50, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());

			// 1st task: block first executor slot with sleeping
			executor.submit(new Runnable() {
				public void run() {
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						throw new RuntimeException(e);
					}
				}
			});

			Thread.sleep(100); // wait a while to ensure that first task is really started

			// 2nd task: set maximum pool size to 1; this will lead ThreadPoolExecutor interrupting this thread although it is not idle
			final AtomicBoolean interrupted = new AtomicBoolean(false);
			executor.submit(new Runnable() {
				public void run() {
					executor.setCorePoolSize(1);
					executor.setMaximumPoolSize(1); // ThreadPoolExecutor will try to interrupt 3-1=2 tasks
					interrupted.set(Thread.currentThread().isInterrupted());
				}
			}).get(); // submit and wait

			assert !interrupted.get() : "thread was interrupted, bug still exists!";
	}


	public static void main(final String[] args) {
		try {
			new Test().test();
		} catch (final Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
		System.exit(0);
	}
}
---------- END SOURCE ----------

Comments
EVALUATION I am very confused as to what the problem is that is being reported here. As described in 6576792 a number of changes to the ThreadPoolExecutor in JDK 7 b08 make it much more likely that an interrupt would hit client code - this is a regression. The fix for 6576792 addresses that regression and was putback in JDK 7 b17. The escape of interrupts into client code was possible always, but less likely in general. However, as the submitter discovered, one case where this can be made to always occur is if you call setCorePoolSize from a task being executed by the pool. The fix for 6576792 addresses this for all JDK versions. However the fixes for JDK 5 and 6 are not yet in a released update. The submitter's test program fails in the current release version of JDK 5 and 6, and in JDK prior to build 17. It passed in JDK 7 b17 onwards and passes in the yet-to-be-released JDK 5 and 6 updates. Unless there is some other issue here that I have overlooked I will be closing this as a duplicate of 6576792.
17-04-2008