4

Reading up on the documentation of ThreadPoolExecutor, I'm confused what the difference is between the following to example usages:

Zero core threads and ten max threads, of which the latter times out after 2 seconds:

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

Ten core threads and ten max threads that both time out after 2 seconds:

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

executor.allowCoreThreadTimeOut(true);

Do these executors behave differently in any way?

Benny Bottema
  • 11,111
  • 10
  • 71
  • 96

2 Answers2

7

You can read the motivation 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); can be used to get this behavior.

More details why no tasks get executed at all if corePoolSize = 0 is specified

From the 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.)

Hence, if you specify corePoolSize = 0 no threads will ever be created, and no tasks will be executed at all.

In practice, however, when the corePoolSize is zero, implementations does create one thread (tested with Sun JDK6 and OpenJDK11). So in practice, the tasks are executed, but no more than one thread is ever created, regardless of what maximumPoolSize is specified. I'm not entirely sure why because according to the spec, it shouldn't create even one.

Below is my test code. This will only ever use one thread, but if you specify corePoolSize=10, it will use 10. If you add allowCoreThreadTimeOut(true), then these threads can timeout.

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();
Enno Shioji
  • 26,542
  • 13
  • 70
  • 109
  • From that link: "The most intuitive approach - set core size to 0, maximum pool size to the bounding value, and the queue to some kind of LinkedQueue or ArrayQueue - fails: no tasks get executed at all (consistently with Javadoc)." Can you please elaborate on why nothing would get executed in example 1? – Benny Bottema Apr 27 '19 at 10:03
  • Added more details @BennyBottema – Enno Shioji Apr 27 '19 at 10:53
  • So even with core threads at 0 and max threads 10, it will not create any threads? – Benny Bottema Apr 27 '19 at 12:41
  • The implementation (Sun JDK6 and Open JDK11) puzzlingly creates exactly one thread at core threads = 0, max threads = 10. I'm not sure why because according to the spec it shouldn't create any threads. Try my test code to see for your self! @BennyBottema – Enno Shioji Apr 27 '19 at 13:00
0

With coreSize=0, only one thread is used to execute tasks until the queue is full. (This is the behavir of Java 1.6+. With Java 1.5, no tasks will be executed before the queue is full. see ThreadPoolExecutor with corePoolSize 0 should not execute tasks until task queue is full)

With coreSize=n and allowCoreThreadTimeOut=true, up to n threads will be created to execute tasks until the queue is used.

Nano
  • 111
  • 1
  • 5