I am using a bounded LinkedBlockingQueue in a multi threaded environment. I have a single threaded consumer which performs the following using a ScheduledExecutorService every N seconds:
try {
current = queue.poll(properties.getPollTimeout(), TimeUnit.SECONDS);
if (null == current) {
return;
}
if (isTimeToLiveExceeded(current)) {
cancel();
return;
}
if (current.isReady()) {
current.execute();
return;
}
log.debug("Adding back to the queue");
add(current);
} catch (Throwable e) {
log.warn("Caught unexpected exception", e);
add(current);
}
The add method calls offer with retries:
private boolean add(IQueuedOperation op) {
boolean result = false;
int retries = properties.getQueueOfferRetries();
while (!result && retries-- > 0) {
try {
result = queue.offer(op, properties.getQueueRetryTimeout(), TimeUnit.SECONDS);
} catch (InterruptedException e) {
log.debug("Caught exception trying to add operation to the queue",e);
result = false;
}
}
return result;
}
The idea is I poll an element from the queue, see if I can execute it, and if not I put it back in the queue.
My problem is as follows: Assuming the queue's size is 1. A possible scenario is that the consumer thread polls and gets an element, so the queue's size is now 0. A different thread inserts a new element to the thread successfuly, size is now 1. The consumer thread fails the isTimeToLiveExceeded and isReady checks, and then needs to add the element back to the queue, but it fails as the queue is now full.
What would be a proper way of ensuring that I always have enough room to insert the element I'm currently processing if it is not time to execute it yet?