Q:

why the maxPoolSize in the ThreadPoolExecutor do nothing?

In the ThreadPoolExecutor class, there is a maxPoolSize to specify the maximum thread pool size. That means if number of threads less than that number, threads in the pool should be executed immediately. But I found it is not the case. It cannot go beyond the corePoolSize actually. I am confused. what is the purpose of the maxPoolSize if it does nothing? Here is my testing program:
I have specified the corePoolSize = 2; maxPoolSize = 6; I have created 5 threads (Runnable). I thought all the 5 threads (Runnable) should running simultaneously. But they are not. Only two of them are running, another 3 are put aside until the first two die.
I have read many posts about the topic. But none can guide me to make the 5 threads running simultaneously.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MyThreadPoolExecutorTest2
{
    private List<MyRunnable> myRunnables = new ArrayList<>();

    public static void main(String[] args)
    {
        new MyThreadPoolExecutorTest2().test();
    }

    public void test()
    {
        int poolSize = 2;
        int maxPoolSize = 6;
        int threadPoolKeepAliveTimeInSec = 30;
        ExecutorService threadPoolExecutor =
                new MySimpleThreadPoolExecutor(poolSize, maxPoolSize, threadPoolKeepAliveTimeInSec);
        int numOfThread = 5;
        System.out.println("Start thread pool test with corePoolSize=" + poolSize + ", maxPoolSize=" + maxPoolSize
                + ", actualThreads=" + numOfThread);
        for (int i = 0; i < numOfThread; i++)
        {
            MyRunnable tempRunnable = new MyRunnable(i + 1, "PoolTest" + (i + 1));
            myRunnables.add(tempRunnable);
            threadPoolExecutor.execute(tempRunnable);
        }
        System.out.println("********* wait for a while");
        try
        {
            Thread.sleep(20000);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }

        System.out.println("^^^^^^^^^^ shutdown them all");
        for (MyRunnable runnable : myRunnables)
        {
            runnable.shutdown();
        }
        System.out.println("Ended thread pool test.");
    }

    public class MyRunnable implements Runnable
    {
        private int id = 0;
        private String name = "";

        private boolean shutdown = false;

        public MyRunnable(int id, String name)
        {
            this.id = id;
            this.name = name;
        }

        @Override
        public void run()
        {
            System.out.println("++++ Starting Thread: " + id + ":" + name);
            while (!shutdown)
            {
                try
                {
                    Thread.sleep(200);
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
            System.out.println("---- Ended Thread: " + id + ":" + name);
        }

        public void shutdown()
        {
            shutdown = true;
        }
    }
}

class MySimpleThreadPoolExecutor extends ThreadPoolExecutor
{
    private static int peakActiveThreads = 0;
    private String taskInfo = "";

    public MySimpleThreadPoolExecutor(int nThreads, int maxThreads, int threadPoolKeepAliveTimeInSec)
    {
        super(nThreads, maxThreads, threadPoolKeepAliveTimeInSec * 1000L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
        System.out.println("MySimpleThreadPoolExecutor::MySimpleThreadPoolExecutor(), threadPoolSize=" + nThreads
                + ", maxThreadCount=" + maxThreads + ", threadPoolKeepAliveTimeInSec=" + threadPoolKeepAliveTimeInSec);
    }

    @Override
    public void beforeExecute(Thread t, Runnable r)
    {
        int activeCount = getActiveCount();
        if (MySimpleThreadPoolExecutor.peakActiveThreads < activeCount)
        {
            MySimpleThreadPoolExecutor.peakActiveThreads = activeCount;
        }
        taskInfo = r.toString();
        String msg =
                "BeforeE thread(name:id)::" + t.getName() + ":" + t.getId() + ", task::" + r.toString() + "\n"
                        + threadPoolInfoStr();
        System.out.println("ThreadInfo before, MySimpleThreadPoolExecutor::beforeExecute(), " + msg);
        super.beforeExecute(t, r);
    }

    @Override
    public void execute(Runnable command)
    {
        beforeExecute(Thread.currentThread(), command);
        super.execute(command);
    }

    public String threadPoolInfoStr()
    {
        return String.format("Thead: %s/%d\n[PoolSize/CorePoolSize] [%d/%d]\nActive: %d\nCompleted: %d\nTask: %d"
                + "\nisShutdown: %s\nisTerminated: %s\npeakActiveThreads: %d\nTaskInfo: %s\nQueueSize: %d", Thread
                .currentThread().getName(), Thread.currentThread().getId(), getPoolSize(), getCorePoolSize(),
                getActiveCount(), getCompletedTaskCount(), getTaskCount(), isShutdown(), isTerminated(),
                MySimpleThreadPoolExecutor.peakActiveThreads, taskInfo, getQueue().size());
    }
}

A:

New threads will only be created up to maxPoolSize once the queue is full.  Before the limit is the one defined at corePoolSize.
Reference: http://www.bigsoft.co.uk/blog/index.php/2009/11/27/rules-of-a-threadpoolexecutor-pool-size

