使用 ThreadPoolExecutor,allowCoreThreadTimeOut 和零核心线程有什么区别?

With ThreadPoolExecutor, what is the difference between allowCoreThreadTimeOut and zero core threads?

阅读 ThreadPoolExecutor 的文档,我很困惑以下示例用法之间的区别:

零个核心线程和十个最大线程,其中后者在 2 秒后超时:

ThreadPoolExecutor executor = new ThreadPoolExecutor(
        0, // core threads
        10, // max threads
        2000, TimeUnit.MILLISECONDS,
        new LinkedBlockingQueue<Runnable>(),
        Executors.defaultThreadFactory()
);

10 个核心线程和 10 个最大线程均在 2 秒后超时:

ThreadPoolExecutor executor = new ThreadPoolExecutor(
        10, // core threads
        10, // max threads
        2000, TimeUnit.MILLISECONDS,
        new LinkedBlockingQueue<Runnable>(),
        Executors.defaultThreadFactory()
);

executor.allowCoreThreadTimeOut(true);

这些执行者的行为是否有任何不同?

你可以阅读动机here

I want something like fixed thread pool (Executors.newFixedThreadPool()) but with threads dying off when they are idle for too long, and re-created when they are needed again.

The most intuitive approach - set core size to 0, maximum pool size to the bounding value, and the queue to [an unbounded queue] - fails: no tasks get executed at all (consistently with Javadoc but - IMHO - a little bit counterintuitively).

executor.allowCoreThreadTimeOut(true); 可用于获得此行为。

如果指定 corePoolSize = 0,为什么根本没有任务执行的更多详细信息

来自 Javadoc,

Using an unbounded queue (for example a LinkedBlockingQueue without a predefined capacity) will cause new tasks to wait in the queue when all corePoolSize threads are busy. Thus, no more than corePoolSize threads will ever be created. (And the value of the maximumPoolSize therefore doesn't have any effect.)

因此,如果您指定 corePoolSize = 0,将永远不会创建线程,也不会执行任何任务。

然而,在实践中,当 corePoolSize 为零时,实现会创建一个线程(使用 Sun JDK6 和 OpenJDK11 进行测试)。所以在实践中,任务 被执行 ,但不会创建超过一个线程,无论指定什么 maximumPoolSize。我不完全确定为什么,因为根据规范,它甚至不应该创建一个。

下面是我的测试代码。这只会使用一个线程,但是如果您指定 corePoolSize=10,它将使用 10 个。如果您添加 allowCoreThreadTimeOut(true),那么这些线程可能会超时。

LinkedBlockingQueue<Runnable> q = new LinkedBlockingQueue<Runnable>();
ThreadPoolExecutor executor = new ThreadPoolExecutor(
        0, // core threads
        10, // max threads
        2, TimeUnit.MILLISECONDS,
        q
);

for (int i = 0; i < 10; i++) {
    final int j = i;
    executor.execute(() ->
        {
           try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           System.out.println(
               "TaskNo:" + j + ":" + Thread.currentThread().getName()
           );
         });
}

executor.shutdown();