Reputation: 22357
This is the cached thread pool:
new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
and this is the fixed ThreadPoolExecutor:
new ThreadPoolExecutor( 0, 20, 60L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
The first one can create INTEGER.MAX_VALUE number of threads, which is undesired in my case.
The second one, is incorrect. You cannot use a mininum of zero threads and a maximum of 20 threads with a LinkedBlockingQueue.
From the documentation:
http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html
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.)
The use of a SynchronousQueue in the first case, CachedThreadPool really serves no purpose as a queue. It will only create threads as needed and need a high upper bound.
A good default choice for a work queue is a SynchronousQueue that hands off tasks to threads without otherwise holding them. Here, an attempt to queue a task will fail if no threads are immediately available to run it, so a new thread will be constructed. This policy avoids lockups when handling sets of requests that might have internal dependencies. Direct handoffs generally require unbounded maximumPoolSizes to avoid rejection of new submitted tasks. This in turn admits the possibility of unbounded thread growth when commands continue to arrive on average faster than they can be processed.
Now, what I am after is this:
What I want is for an executor that you can submit work to, that uses a queue if maxThreads are all busy, but that also allows the threads to go idle, and not take up any resources when there are no work.
The use of:
ThreadPoolExecutor ex = new ThreadPoolExecutor(0, threads, 60L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
ex.setKeepAliveTime(idletime, TimeUnit.MILLISECONDS);
I am not sure what implication it has. The documentation seems to only explain the use of an unbounded LinkedBlockingQueue, which I am not really sure what that means, since the constructor creates one with a max capacity of Integer.MAX_VALUE.
The documentation also states:
(And the value of the maximumPoolSize therefore doesn't have any effect.)
What I want is a minimum thread pool size and a maximum thread pool size that queues up work and lets threads go idle when there is no work.
EDIT
Reading this question and the last part made me consider if one should create a
new ThreadPoolExecutor(20, ??irrelevant??, 60L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
Which would create 20 threads that goes idle if
ex.setKeepAliveTime(60L, TimeUnit.MILLISECONDS);
is set.
Is this an correct assumption?
Upvotes: 1
Views: 1877
Reputation: 40256
What I want is a minimum thread pool size and a maximum thread pool size that queues up work and lets threads go idle when there is no work.
This is precicely what a fixed-thread pool with unbounded queue gives you. In short defining a thread-pool like
new ThreadPoolExecutor( 0, 20, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
Is all you need. What you get is a thread-pool which has at most 20 threads, and a work queue which can accept an 'infinite' number of tasks.
So what if the queue is empty? The ThreadPool will have the 20 threads still alive and waiting on the queue. When they wait on the queue the threads suspend and do no work.
The one update I would make is to change 0L, TimeUnit.MILLISECONDS
to something a bit higher like 1L, TimeUnit.SECONDS
. This is the thread-idle period, you should let the thread stay alive for a little longer before you shut it down.
In short, a thread-pool does what I believe you want. There may be something I am missing if so let me know in comments.
Upvotes: 1