ThreadPoolExecutor#getPoolSize与ThreadPoolExecutor#getActiveCount有什么区别

问题描述

我一直在玩ThreadPoolExecutor。我需要一个返回当前正在运行的线程数的方法。因此,我决定使用ThreadPoolExecutor#getActiveCount

但是,当我测试自己的方法时,我注意到一些有趣的东西:ThreadPoolExecutor#getActiveCount始终等于ThreadPoolExecutor#getPoolSize

下面是重现它的示例代码

class ExecutorTest {

        private ThreadPoolExecutor executor;

        Executortest() {
            executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
        }

        @Test
        void test() {
            executor.execute(makeRunnable(100,"1"));
            printExecutorState();
            executor.execute(makeRunnable(100,"2"));
            printExecutorState();
            executor.execute(makeRunnable(100,"3"));
            printExecutorState();
            executor.execute(makeRunnable(100,"4"));
            printExecutorState();

            System.out.println("==Changing thread core&max pool size==");
            executor.setCorePoolSize(2);
            executor.setMaximumPoolSize(2);

            printExecutorState();
            assertthat(executor.getMaximumPoolSize()).isEqualTo(2);
            assertthat(executor.getActiveCount()).isEqualTo(4);
        }

        private Runnable makeRunnable(long workTime,String name) {
            return () -> {
                long startTime = System.currentTimeMillis();
                System.out.println("Running " + name);
                while (System.currentTimeMillis() - startTime < workTime) {
                }
                System.out.println("Exited " + name);
            };
        }

        private void printExecutorState() {
            int poolSize = executor.getPoolSize();
            int corePoolSize = executor.getCorePoolSize();
            int maxPoolSize = executor.getMaximumPoolSize();
            int running = executor.getActiveCount();

            String currentState = String.format(
                    "poolSize=%d,corePoolSize=%d,maxPoolSize=%d,running=%d",poolSize,corePoolSize,maxPoolSize,running
            );

            System.out.println(currentState);
        }
    }

它打印以下内容

Running 1
poolSize=1,corePoolSize=10,maxPoolSize=10,running=1
Running 2
poolSize=2,running=2
Running 3
poolSize=3,running=3
Running 4
poolSize=4,running=4
==Changing thread core&max pool size==
poolSize=4,corePoolSize=2,maxPoolSize=2,running=4

现在的问题是这些方法之间有什么区别?使用ThreadPoolExecutor#getPoolSize来检索正在运行的线程数有意义吗?

解决方法

如果仅查看javadoc的功能,便可以得到不同之处:

/**
* Returns the current number of threads in the pool.
*
* @return the number of threads
*/
public int getPoolSize() 

/**
* Returns the approximate number of threads that are actively
* executing tasks.
*
* @return the number of threads
*/
public int getActiveCount()

getPoolSize()将包含池中未执行任何任务的线程,但 getActiveCount()中将不包括该线程。在初始代码中,您创建了线程池,线程池的大小为10,但是提交了4个任务。因此,池大小为10,活动计数为4。因此,使用ThreadPoolExecutor#getPoolSize来检索正在运行的线程数是错误。它只是为您提供创建的线程数,活动运行的线程数由活动计数给出。

在您的用例中,请注意即使将最大池大小减小为2,池大小仍为4。所以发生的是4个线程正在执行4个任务。

完成任务的前两个线程将终止。届时,池大小将减小为2,活动池仍将为2(其他正在进行的任务)。

其他两个线程完成任务时,池大小将保持2(核心池大小),但由于没有任何任务在运行,活动池将恢复为0。