I'm running Ian Darwins producer-consumer for Java 1.5 example (http://www.javafaq.nu/java-example-code-969.html) from Eclipse Ganymede. I added some output immediately before the threads return statements to assure myself that the return was being reached when the stop signal was sent. I see that all threads have reached their return. Using the windows task manager I can see a javaw.exe process start when I start my app and this process is still shown after the last line of my main has been executed. So something is still running when the main exits.
It looks to me like any consumer which reaches the take() step before the done flag is set will sit and wait for an object to be available and will never actually see that done flag being set. This probably comes up regularly if the consumer is much faster than the producer, or there are fewer producers than consumers.
The fixes I can think of:
1) Make Consumer threads Daemons, so any Consumers waiting in the take() method will die when the application ends. This works, but I generally like to explicitly end Threads when I can, so I avoid this one (I consider it a bit of a hack)
2) When the done flag is set, also interrupt your consumers (and producers as well) so they are forced to see the done flag. My preference, when I use this method, is to (a) not use while(true) but instead use while(!done). (b) Put the catch for the InterruptedException INSIDE the while loop. We will catch interrupted exceptions but maybe that shouldn't kill the thread.
3) You could use a poison pill approach. The problem here is caused by the fact that the Consumer is sitting in a take() statement and there is nothing to take(). So you could make the producer give consumers a sign that the queue is complete, take this poison and die. This is especially useful if you want the Consumers to finish any backlog of objects in the queue before they die (if there is a backlog, they can keep churning through the list until they reach poison). To make it work you need a fixed object that the Producer can supply and the Consumer can recognize as a signal to end. When the Producer gets the done flag, it puts the signal into the queue and then comes to an end itself. Note that you may have multiple producers and so may have multiple poison signals, that is okay. Then the Consumer churns through the queue and gets to a Poison object, recognizes it and dies. I usually make it add the poison back to the queue in case there are more Consumers than Producers to make sure all Consumers get a Poison pill. Something like this:
Joined: Dec 13, 2004
Thanks for the great reply! You were right on the money, the consumer was so much faster than the producer that it ended up just sitting on the empty queue. Following your explanation I had the producer put a signal object on the queue before exiting, problem solved.
Thanks again for the great explanation of what was involved,