[concurrency-interest] Thread Pools
peger at automotive.com
Mon Jul 24 13:54:40 EDT 2006
I appreciate all your replies, and I definitely realize the design
tradeoffs that need to be made for the sake of efficiency. I believe I
tried to hack in the below "poll() before idling thread" + "keep approx
idle count" approach into the JDK code, though I was not very familiar
with the code and gave up quickly.
Briefly, my use-case for having a thread pool behave as requested is
1) multiple thread pools (10 or so)
2) each with specific priority / thread group / naming / specific Thread
3) desire to let each pool grow very large (~1000 threads) due to
possibility of slow I/O in one or more of the pools & desire for maximum
concurrency in the tasks
4) pools hand off work between each other for roughly ~1000 concurrent
By not having #4 from previous message, the number of threads in the
system can peak up to 10K threads, even though there are only 1000
concurrent tasks. The conflicting needs are: 1) to have a large CORE
size for the pools to allow many concurrent threads when the I/O is
slow, but 2) to keep the average pool size low when the I/O is fast
(normal case), all the while 3) keeping the TOTAL thread count (globally
and per-pool) as low as reasonable.
I won't say the architecture is ideal, but it is much easier to swap out
thread-pool implementations than it is to rewrite the app. Hope this
clarifies things a little.
From: concurrency-interest-bounces at cs.oswego.edu
[mailto:concurrency-interest-bounces at cs.oswego.edu] On Behalf Of Martin
Sent: Sunday, July 23, 2006 1:31 PM
To: concurrency-interest at cs.oswego.edu
Subject: [concurrency-interest] Thread Pools
concurrency-interest-request at cs.oswego.edu wrote:
> Date: Sat, 22 Jul 2006 07:56:06 -0400
> From: Doug Lea <dl at cs.oswego.edu>
> Subject: Re: [concurrency-interest] Thread Pools
> To: Patrick Eger <peger at automotive.com>
> Cc: concurrency-interest at cs.oswego.edu
> Message-ID: <44C21256.5080306 at cs.oswego.edu>
> Content-Type: text/plain; charset=windows-1252; format=flowed
> Patrick Eger wrote:
>>IE I would like a:
>>1) potentially infinite queue of tasks (currently using a
>>2) executed by up to MAX threads concurrently
>>3) which go away after a period of inactivity, allowing the pool to
>>shrink to MIN (or zero) size
>>4) preferring to use already existing threads rather than creating new
> All but (4) are straightforward.
> By (4) I assume you mean to use an existing thread only if
> it is "idle". This is just about impossible to deterministically
> guarantee, at least when using an unbounded queue.
> The pool cannot know for sure whether an existing thread is idle.
> It only knows whether there are fewer or more than target number
> of threads, and whether the queue is full, which it never is for
> unbounded ones. Problematic cases include those where an
> idle-looking thread is in the process of dequeuing a task and
> so will momentarily run it. You might be content with an
> implementation that ignores such cases and approximates (4)
> by for example, counting threads blocked on workQueue.take.
> But it would probably be a bad idea for us to add such capabilities --
> they invite a stream of bug reports when "approximately" doesn't
> cover particular use cases well. (For example, here, it is hard
> to avoid the pathology of a large number of threads trying
> to submit tasks at the same time, and all of them thinking that
> they don't need to create a new thread because there is an idle one.)
I'm sympathetic to Patrick's suggestion; users generally
assume that ThreadPoolExecutor prefers reusing idle
threads. I think we can avoid the above pathology by
simply checking queue size after enqueuing,
and changing our minds and adding a
new thread if the queue size is ever greater than 1.
Then at worst there will be one excess task waiting while all
workers are busy.
If we maintained good idleTaskCount statistics, we
could be more aggressive and only add a new thread if
idleTaskCount() < workQueue.size().
Maintaining an idle task count seems relatively expensive,
especially if the pool size is large.
Perhaps we could optimize it by
Try queue.poll(); if a task is available immediately, run it.
else increment idleCount while using timed poll() or take().
There are lots of design choices here.
> ThreadPoolExecutor tries to cover as wide a set of use cases as
> can all be handled by the same overall design. It does cover most
> common uses. But even at that, we have had to revamp parts of the
> implementation now and then to get rid of unwanted unforeseen
> interactions among various parameters and methods.
> So, if you really need this behavior, it looks like you will
> need a custom implementation. Or you might decide that plain
> newFixedThreadPools are OK for your application after all?
Concurrency-interest mailing list
Concurrency-interest at altair.cs.oswego.edu
More information about the Concurrency-interest