I’m using java.util.concurrent.BlockingQueue in a very simple producer-consumer scenario. E.g. this pseudo code depicts the consumer part:
class QueueConsumer implements Runnable {
@Override
public void run() {
while(true)
{
try {
ComplexObject complexObject = myBlockingQueue.take();
//do something with the complex object
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
So far so good. In the javadoc of the blocking queue I read:
A BlockingQueue does not intrinsically
support any kind of “close” or
“shutdown” operation to indicate that
no more items will be added. The needs
and usage of such features tend to be
implementation-dependent. For example,
a common tactic is for producers to
insert special end-of-stream or poison
objects, that are interpreted
accordingly when taken by consumers.
Unfortunately because of the generics in use and the nature of ComplexObject it’s not trivial to push a “poison object” into the queue. So this “common tactic” is not really convenient in my scenario.
My question is: what other good tactics/patterns can I use to “close” the queue?
Thank you!
If you have a handle to the consumer thread, you can interrupt it. With the code you gave, that will kill the consumer. I would not expect the producer to have this; it would probably have to callback to the program controller somehow to let it know it’s done. Then the controller would interrupt the consumer thread.
You can always finish doing work before obeying the interrupt. For instance:
I would actually prefer that to somehow poisoning the queue anyway. If you want to kill the thread, ask the thread to kill itself.
(It’s nice to see someone handling
InterruptedExceptionproperly.)There seems to be some contention about the handling of interruptions here. First, I would like everyone to read this article.
Now, with the understanding that no one actually read that, here’s the deal. A thread will only receive an
InterruptedExceptionif it was currently blocking at the time of interrupt. In this case,Thread.interrupted()will returnfalse. If it was not blocking, it will NOT receive this exception, and insteadThread.interrupted()will returntrue. Therefore, your loop guard should absolutely, no matter what, checkThread.interrupted(), or otherwise risk missing an interruption to the thread.So, since you are checking
Thread.interrupted()no matter what, and you are forced to catchInterruptedException(and should be dealing with it even if you weren’t forced to), you now have two code areas which handle the same event, thread interruption. One way to handle this is normalize them into one condition, meaning either the boolean state check can throw the exception, or the exception can set the boolean state. I choose the later.Edit: Note that the static Thread#interrupted method clears the the interrupted status of the current thread.