[concurrency-interest] Thread Pools

Martin Buchholz Martin.Buchholz at Sun.COM
Sun Jul 23 16:31:16 EDT 2006



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 
>>LinkedBlockingQueue)
>>
>>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 ones
>>
> 
> 
> 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.

Martin

> 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?
> 
> -Doug


More information about the Concurrency-interest mailing list