I’m looking to have a ThreadPoolExecutor where I can set a corePoolSize and a maximumPoolSize and what happens is the queue would hand off task immediately to the thread pool and thus create new threads until it reaches the maximumPoolSize then start adding to a queue.
Is there such a thing? If not, are there any good reason it doesn’t have such a strategy?
What I want essentially is for tasks to be submitted for execution and when it reaches a point where it is essentially going to get ‘worst’ performance from having too many threads (by setting maximumPoolSize), it would stop adding new threads and work with that thread pool and start queuing, then if the queue is full it rejects.
And when load comes back down, it can start dismantling threads that are unused back to the corePoolSize.
This makes more sense to me in my application than the ‘three general strategies’ listed in http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html
Note: these implementations are somewhat flawed and non-deterministic. Please read the entire answer and the comments before using this code.
How about creating a work queue that rejects items while the executor is below the maximum pool size, and starts accepting them once the maximum has been reached?
This relies on the documented behavior:
“If a request cannot be queued, a new thread is created unless this
would exceed maximumPoolSize, in which case, the task will be
rejected.”
Note: Your question surprised me because I expected your desired behavior to be the default behavior of a ThreadPoolExecutor configured with a corePoolSize < maximumPoolSize. But as you point out, the JavaDoc for ThreadPoolExecutor clearly states otherwise.
Idea #2
I think I have what is probably a slightly better approach. It relies on the side-effect behavior coded into the
setCorePoolSizemethod inThreadPoolExecutor. The idea is to temporarily and conditionally increase the core pool size when a work item is enqueued. When increasing the core pool size, theThreadPoolExecutorwill immediately spawn enough new threads to execute all the queued (queue.size()) tasks. Then we immediately decrease the core pool size, which allows the thread pool to shrink naturally during future periods of low activity. This approach is still not fully deterministic (it is possible for the pool size to grow above max pool size, for example), but I think it is in almost all cases it is better than the first strategy.Specifically, I believe this approach is better than the first because:
–