[concurrency-interest] how to auto-terminate producer-consumer service

Mike Quilleash mike.quilleash at subexazure.com
Tue Mar 27 12:39:39 EDT 2007

I've solved this in the past by using ExecutorCompletionService (ECS).
Something like the following:

1) Create an ECS for the producer.
2) Create an ECS for the consumer.
3) Submit all the producers.
4) Submit all the consumers.
5) Loop over the producer ECS doing a .take() for each submitted
6) Now all the producers have completed, submit a poison pill to the
queue for each consumer.
7) Each consumer will read one poison pill and die.
8) Loop over the consumer ECS doing a .take() for each submitted

2) and 8) are optional if you don't care about waiting for the consumers
to finish.

This leaves the producers and consumers separated each other with only
the submitting thread needing to know how many of each there was.



-----Original Message-----
From: concurrency-interest-bounces at cs.oswego.edu
[mailto:concurrency-interest-bounces at cs.oswego.edu] On Behalf Of Timo
Sent: 27 March 2007 17:17
To: concurrency-interest at cs.oswego.edu
Subject: [concurrency-interest] how to auto-terminate producer-consumer

This is about chapter 7.2 in jcip but I don't want to shutdown or cancel
the service but merely there's finite amount of work to do and when it's
done the service is supposed to shutdown itself.

So Nproducer threads and Nconsumer thread connected via a BlockingQueue.
problem: when the producers have done their job how do the consumer
know? And even if they would know they would be blocked in take()

One solution is presented in 7.2.2 but I waiting until the producers are
done and then interupting the consumers just to tell them to finished
their work and then shutdown would be reallly weird coding.

7.2.3 suggest a poison pill. This is actually what I did but I'm not
happy with it. If each producer puts a single poison pill into the queue
it will only work if Nproducer>=Nconsumer. Letting each producer put
Nconsumer poison pills in the queue will only work for Nproducer==1
otherwise all consumers will  be dead by the time other producers are
still producing. And finally IMHO it's bad design that the producer are
coupled to the consumer by having to know what many consumers are
actually out there.

So came up with the idea that not the producers are putting the poison
pills into the queue but actually the thread that started the producers

			// start producers and consumers

			// wait until producers are finished
			for( final Thread t : producers )

			// put Nconsumer poison pill in the queue, put()
will block
                        for( int i = 0; i < consumers.length; i++ )
                                queue.put( POISON_PILL );

			// and finally wait for the consumers to swallow
the poison pill
                        for( final Thread i : consumers )

(I yet didn't have had a closer look at the new Executer stuff :-)

This works. But I don't like it. The consumers could peek() before
take() and watch out for poison pills but I would have to lock the queue
for this case and that's not worth it.

Isn't there a better solution? Some Queue with poison pilll
functionality comes to my mind but it will be somewhat tricky how to
handle multiple producers...
Concurrency-interest mailing list
Concurrency-interest at altair.cs.oswego.edu

 This e-mail is bound by the terms and conditions described at http://www.subexazure.com/mail-disclaimer.html

More information about the Concurrency-interest mailing list