ThreadPoolExecutor#getPoolSize() vs ThreadPoolExecutor#getActiveCount() 有什么区别

ThreadPoolExecutor#getPoolSize() vs ThreadPoolExecutor#getActiveCount() what is the difference

我一直在玩ThreadPoolExecutor。我需要一个 returns 当前线程数 运行 的方法。所以我决定使用 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, corePoolSize=10, maxPoolSize=10, running=2
Running 3
poolSize=3, corePoolSize=10, maxPoolSize=10, running=3
Running 4
poolSize=4, corePoolSize=10, maxPoolSize=10, 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,因为没有任务 运行。