Issue
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?
Solution
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();
Answered By - Enno Shioji
Answer Checked By - Terry (JavaFixing Volunteer)