4

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());
    }
}
peterboston
  • 877
  • 1
  • 12
  • 24
  • 1
    This thread discusses a similar question: https://stackoverflow.com/questions/17659510/core-pool-size-vs-maximum-pool-size-in-threadpoolexecutor – Michael Dec 25 '17 at 20:23

2 Answers2

6

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

HaroldSer
  • 2,025
  • 2
  • 12
  • 23
3

More threads are added only if the queue is full.

Since your LinkedBlockingQueue is not bounded, it will never be full. Therefore, there will never be more than the core pool size of threads in the pool.

Use a TransferQueue or use a bounded queue to fix this.