I don't think the current implementation is actually wrong under
normal use (where you just configure the gbean in xml and don't
change its settings at runtime).
I think it would be better to set up the executor in its constructor
(keeping the waitWhenBlocked as a constructor parameter). There's a
constructor for ThreadPoolExecutor we can use that lets us set
everything at once.
I think the wait when blocked configuration is correct as it stands.
I suggest that using the LinkedBlockingQueue is appropriate when
waitWhenBlocked is false but not when its true.
IMO the caller-runs policy is not appropriate for use in j2ca since
the work manager can notify you if the work is rejected. Thus tying
up your own thread is not appropriate since it eliminates the
possibility of the caller taking corrective action.
thanks
david jencks
On Sep 2, 2007, at 8:46 AM, Manu George wrote:
Hi,
I was investigating why setting the resourceAdapter poolsize
to 1 and using it in an Mdb for sequential message processing was
failing and found that the org.apache.geronimo.pool.ThreadPool class
in geronimo contains a ThreadPoolExecutor instance created with the
constructor
new ThreadPoolExecutor(
poolSize, // core size
poolSize, // max size
keepAliveTime, TimeUnit.MILLISECONDS,
new SynchronousQueue());
The default behaviour is to reject the Runnables supplied when the no
of active threads equals the pool size.
Now the ThreadPool class has a setWaitWhenBlocked method which when
called makes it wait. Setting this makes the pool enter into a
deadlock. The reason for this is the WaitWhenBlockedPolicy used to
process rejection. In this class there is a
executor.getQueue().put(r);
Now the API docs mention that once you handoff the queue to a
ThreadPoolExecutor we should not directly modify the queue as it may
result in unpredictable behaviour. So this is a bug.
As a solution for this what I did was
ThreadPoolExecutor p = new ThreadPoolExecutor(
poolSize, // core size
poolSize, // max size
keepAliveTime, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(queueSize));
Now this results in upto queue size of Runnables that can be submitted
of which poolsize will be the no of parallel executions. More than
queue size will be rejected.
We can also set the rejection handler to the CallerRunsPolicy when the
quesize is exceeded and the waitWhenBlocked flag is true.
This results in me getting the scenario working. I am not yet sure why
the SynchronousQueue was used in this case, so thats why I changed the
queuing strategy. So Is this an acceptable approach for fixing this
issue?
Secondly do we want a behaviour of rejection of work items when queue
is full? Setting the CallerRunsPolicy actually results in graceful
degradation when load exceeds capacity by increasing backlog at the
TCP/IP layer. Would be happy if some of the experts would comment on
this
Thanks
Manu