0

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?

Emil Gelman
  • 125
  • 1
  • 10
  • You said, `LinkedBlockingQueue`. Did you mean, `java.util.concurrent.LinkedBlockingQueue`? If that class does not do everything that you want, then you may have to create your own. Should be less than a day's work to implement and test it. More like an hour's work if you "implement" by modifying somebody else's open-source code (e.g., the OpenJDK's LinkedBlockingQueue). – Solomon Slow Jun 30 '20 at 14:14
  • @SolomonSlow yes, I am using `java.util.concurrent.LinkedBlockingQueue` Trying to avoid re implementation. It feels like this should have a native solution and I'm missing something. – Emil Gelman Jun 30 '20 at 14:25
  • 1
    OK, so, You're either going to have to wrap something around that, or you're going to have to implement an augmented version of that. Either way, you'd need a new "atomic" function, maybe call it "borrow()" that would `poll()` the queue, and also, temporarily reduce the capacity by one iff the `poll()` was successful. Then there would have to be one or two other new functions that let you "return" what you borrowed--either put back the item and restore the original capacity, or just restore the original capacity. – Solomon Slow Jun 30 '20 at 14:31

0 Answers0