views:

287

answers:

4

The title of this question makes me doubt if this exist, but still:

I'm interested in whether there is an implemented of Java's BlockingQueue, that is bounded by size, and never blocks, but rather throws an exception when trying to enqueue too many elements.

Edit - I'm passing the BlockingQueue to an Executor, which I suppose uses its add() method, not offer(). One can write a BlockingQueue that wraps another BlockingQueue and delegates calls to add() to offer().

+4  A: 

Edit: Based on your new description I believe that you're asking the wrong question. If you're using a Executor you should probably define a custom RejectedExecutionHandler rather than modifying the queue. This only works if you're using a ThreadPoolExecutor, but if you're not it would probably be a better idea to modify the Executor rather than the queue.

It's my opinion that it's a mistake to override offer and make it behave like add. Interface methods constitute a contract. Client code that uses blocking queues depends on the methods actually doing what the documentation specifies. Breaking that rule opens up for a world of hurt. That, And it's inelegant.


The add() method on BlockingQueues does that, but they also have an offer() method which is generally a better choice. From the documentation for offer():

Inserts the specified element at the tail of this queue if it is possible to do so immediately without exceeding the queue's capacity, returning true upon success and false if this queue is full. This method is generally preferable to method add(E), which can fail to insert an element only by throwing an exception.

This works for all such queues regardless of the specific implementation (ArrayBlockingQueue, LinkedBlockingQueue etc.)

BlockingQueue<String> q = new LinkedBlockingQueue<String>(2);
System.out.println(q.offer("foo")); // true
System.out.println(q.offer("bar")); // true
System.out.println(q.offer("baz")); // false
Emil H
A: 

One can write a BlockingQueue that wraps another BlockingQueue and delegates calls to add() to offer().

If that is supposed to be a question ... the answer is "Yes", but you can do it more neatly by creating a subclass that overrides the add(). The only catch (in both cases) is that your version of add cannot throw any checked exceptions that aren't in the method you are overriding, so your "would block" exception will need to be unchecked.

Stephen C
The problem with that is that your subclass's add() method now behaves differently to the base class's add() - thus violating the substitution principle.
Visage
@Visage: Well yes, but sometimes you've got to violate good design principles a bit to make things work. In this case, I would expect (and hope) that the author makes sure that this "non-standard" class is used in a very narrow context. Certainly it would be a bad idea to expose it in a public API.
Stephen C
A: 

this is sad, you cannot block, there are so many use cases where you would want to block, the whole idea of providing your own bounded blocking queue to the executor has no meaning.

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
            if (runState == RUNNING && workQueue.***offer***(command)) {
                if (runState != RUNNING || poolSize == 0)
                    ensureQueuedTaskHandled(command);
            }
            else if (!addIfUnderMaximumPoolSize(command))
                reject(command); // is shutdown or saturated
        }
    }
A: 

A simple use case to get queries executed from source db in batch (executor), enrich in batch and put into another db (executor), you would want to execute queries only as fast as they are being put into another db. In which case, the dest executor should accept a blocking bounded executor to solve the problem than keep polling and checking how many were completed to execute more queries.

oops more, see my remainder comment: