I have a blocking queue of objects.
I want to write a thread that blocks till there is a object on the queue. Similar to the functionality provided by BlockingQueue.
The only thing I'm aware of that does this is BlockingBuffer in Apache Commons Collections:
If either get or remove is called on an empty Buffer, the calling thread waits for notification that an add or addAll operation has completed.
get()
is equivalent to peek()
, and a Buffer
can be made to act like BlockingQueue
by decorating a UnboundedFifoBuffer with a BlockingBuffer
Not an answer per se, but: JDK-6653412 claims this is not a valid use case.
Do not process the next element until the previous element is processed succesfully.
public void run() {
Object lastSuccessfullyProcessedElement = null;
while (!exit) {
Object obj = lastSuccessfullyProcessedElement == null ? queue.take() : lastSuccessfullyProcessedElement; // blocking
boolean successful = process(obj);
if(!successful) {
lastSuccessfullyProcessedElement = obj;
} else {
lastSuccessfullyProcessedElement = null;
}
}
}
peek()
and checking if the value is null is not CPU efficient.I have seen CPU usage going to 10% on my system when the queue is empty for the following program.
while (true) {
Object o = queue.peek();
if(o == null) continue;
// omitted for the sake of brevity
}
Adding sleep()
adds slowness.
Adding it back to the queue using putLast
will disturb the order. Moreover, it is a blocking operation which requires locks.
Looks like BlockingQueue itself doesn't have the functionality you're specifying.
I might try to re-frame the problem a little though: what would you do with objects you can't "process correctly"? If you're just leaving them in the queue, you'll have to pull them out at some point and deal with them. I'd reccommend either figuring out how to process them (commonly, if a queue.get() gives any sort of invalid or bad value, you're probably OK to just drop it on the floor) or choosing a different data structure than a FIFO.
You could use a LinkedBlockingDeque and physically remove the item from the queue (using takeLast()
) but replace it again at the end of the queue if processing fails using putLast(E e)
. Meanwhile your "producers" would add elements to the front of the queue using putFirst(E e)
.
You could always encapsulate this behaviour within your own Queue
implementation and provide a blockingPeek()
method that performs takeLast()
followed by putLast()
behind the scenes on the underlying LinkedBlockingDeque
. Hence from the calling client's perspective the element is never removed from your queue.
The quick answer is, not there's not really a way have a blocking peek, bar implementing a blocking queue with a blocking peek() yourself.
Am I missing something?
peek() can be troublesome with concurrency -
Sounds like you might be better off actually removing the item and process it using a Chain-of-responsibility pattern
Edit: re: your last example: If you have only 1 consumer, you will never get rid of the object on the queue - unless it's updated in the mean time - in which case you'd better be very very careful about thread safety and probably shouldn't have put the item in the queue anyway.