JDK-7028444 : ThreadPoolExecutor fails to halt extra threads if reconfigured to a smaller pool
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util.concurrent
  • Affected Version: 6
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: linux
  • CPU: x86
  • Submitted: 2011-03-17
  • Updated: 2012-03-20
  • Resolved: 2011-05-16
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_22"
Java(TM) SE Runtime Environment (build 1.6.0_22-b04)
Java HotSpot(TM) 64-Bit Server VM (build 17.1-b03, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Linux deluge 2.6.35-27-generic #48-Ubuntu SMP Tue Feb 22 20:25:46 UTC 2011 x86_64 GNU/Linux


A DESCRIPTION OF THE PROBLEM :
If a ThreadPoolExecutor is reconfigured via setMaximumPoolSize() to a lower number of threads, existing threads beyond the new limit are not terminated.

The intent seems to be to terminate them, but the implementation doesn't actually work.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run the attached source code.
Note that after reconfiguration, there are still 10 threads in the pool, but the new executor configuration specifies a maximum of 5 threads.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Using the latest (2011/03/17)  jsr166.jar from http://g.oswego.edu/dl/concurrency-interest/, I get the expected results:

oliver@deluge:~$ java -Xbootclasspath/p:jsr166.jar TestTPEShrink
Initially, pool size = 0
After execution, pool size = 10
After reconfiguration, pool size = 5
After reconfiguration and execution, pool size = 5



ACTUAL -
Using Java 1.6.0_22, I get these incorrect results:

oliver@deluge:~$ java TestTPEShrink
Initially, pool size = 0
After execution, pool size = 10
After reconfiguration, pool size = 10
After reconfiguration and execution, pool size = 10


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.util.*;
import java.util.concurrent.*;

public class TestTPEShrink {
    private static void runSomeTasks(ExecutorService executor) throws Exception {
        List<Future<?>> completionList = new ArrayList<Future<?>>();
        for (int i = 0; i < 100; ++i) {
            completionList.add(executor.submit(new Runnable() {
                    public void run() {
                        /* nothing */
                    }
                }));
        }
        
        for (Future<?> completion : completionList)
            completion.get();
    }

    public static void main(String[] args) throws Exception {
        // create a 10-thread executor

        ThreadPoolExecutor executor =
            new ThreadPoolExecutor(10, // core pool size
                                   10, // max pool size
                                   Long.MAX_VALUE,  // keepalive
                                   TimeUnit.MILLISECONDS, // keepalive unit
                                   new LinkedBlockingQueue<Runnable>());

        System.err.println("Initially, pool size = " + executor.getPoolSize());

        // run tasks to trigger thread creation
        runSomeTasks(executor);
        System.err.println("After execution, pool size = " + executor.getPoolSize());
        
        // reconfigure the executor to 5 threads
        executor.setCorePoolSize(5);
        executor.setMaximumPoolSize(5);
                                   
        // give it some time to think about it.
        Thread.sleep(5000);

        System.err.println("After reconfiguration, pool size = " + executor.getPoolSize());

        // maybe we need to run some jobs..
        runSomeTasks(executor);
        Thread.sleep(5000);
        System.err.println("After reconfiguration and execution, pool size = " + executor.getPoolSize());

        System.exit(0);
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Use an updated JSR166 jar.
I have not attempted to isolate the bug further.

Comments
EVALUATION This is a duplicate of 6450200.
16-05-2011