5

This question is related with one of my earlier questions..

Previous Post

In there the blocking nature is mentioned as an advantage.

I tried to develop some simple code to demonstrate the blocking nature but I got stuck. I just tried to make a BlockingQueue of size 4 and tried to add 5 elements and ended up with a java.lang.IllegalStateException. Can someone show me a code example for blocking nature of BlockingQueue?


public static void main(String[] args) {
    BlockingQueue<String> bq = new LinkedBlockingQueue<String>(4);

    try {
        bq.offer("A");
        bq.offer("B");
        bq.offer("C");
        bq.offer("D");
        bq.offer("E");

        System.out.println("1 = " + bq.take());
        System.out.println("2 = " + bq.take());
        System.out.println("3 = " + bq.take());
        System.out.println("4 = " + bq.take());
        System.out.println("5 = " + bq.take());
        System.out.println("6 = " + bq.take());
    } catch (Exception e) {
        // TODO: handle exception
        e.printStackTrace();
    }
}

I used this code segment. In this case I am trying to put 5 elements to a queue with size 4. In this case 4 elements (A,B,C,D) should be added to queue. Then I am calling take() method while printing. Shouldn't "E" be inserted automatically to the queue when I call System.out.println("1 = " + bq.take()); ? Because it gets one free slot?

Community
  • 1
  • 1
Chathuranga Chandrasekara
  • 20,548
  • 30
  • 97
  • 138

4 Answers4

11

Were you adding with add, offer, or put? I assume you were using add, since it is the only one that can throw an IllegalStateException; but if you read the table, you'll see that if you want blocking semantics, you should be using put (and take to remove).

Edit: There are a couple of problems with your example.

First I'll answer the question "Why doesn't E get inserted when I call take() the first time?" The answer is that by the time you call take(), you have already tried and failed to insert E. There is then nothing to insert once the space has been freed.

Now if you changed offer() to put(), put("E") will never return. Why? Because it's waiting for some other thread to remove an element from the queue. Remember, BlockingQueues are designed for multiple threads to access. Blocking is useless (actually worse than useless) if you have a single-threaded application.

Here is an improved example:

public static void main(String[] args) {
    final BlockingQueue<String> bq = new LinkedBlockingQueue<String>(4);

    Runnable producer = new Runnable() {
        public void run() {
            try {
                bq.put("A");
                bq.put("B");
                bq.put("C");
                bq.put("D");
                bq.put("E");
            } catch (InterruptedException ex) {
                Thread.currentThread().interrupt(); 
            }
        }
    };
    Runnable consumer = new Runnable() {
        public void run() {
            try {
                System.out.println("1 = " + bq.take());
                System.out.println("2 = " + bq.take());
                System.out.println("3 = " + bq.take());
                System.out.println("4 = " + bq.take());
                System.out.println("5 = " + bq.take());
                System.out.println("6 = " + bq.take());
            } catch (InterruptedException ex) {
                Thread.currentThread().interrupt();
            }
        }
    };
    new Thread(producer).start();
    new Thread(consumer).start();
}

Now the put("E") call will actually succeed, since it can now wait until the consumer thread removes "A" from the queue. The last take() will still block infinitely, since there is no sixth element to remove.

Michael Myers
  • 188,989
  • 46
  • 291
  • 292
2

mmyers beat me to it :P (+1)
that should be what you need, good luck!

NOTE: put() will fail in your example because put() will block until space is available. Since space is never available, the program never continues execution.

==== old answer======

a BlockingQueue is an interface, you'll have to use one of the implementating classes.

The "Blocking Nature" simply states that you can request something from your queue, and if it is empty, the thread it is in will block (wait) until something gets added to the queue and then continue processing.

ArrayBlockingQueue
DelayQueue
LinkedBlockingQueue
PriorityBlockingQueue
SynchronousQueue

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html

//your main collection
LinkedBlockingQueue<Integer> lbq = new LinkedBlockingQueue<Integer>();

//Add your values
lbq.put(100);
lbq.put(200);

//take() will actually remove the first value from the collection, 
//or block if no value exists yet.
//you will either have to interrupt the blocking, 
//or insert something into the queue for the program execution to continue

int currVal = 0;
try {
    currVal = lbq.take();
} catch (InterruptedException e) {
    e.printStackTrace();
}

Robert Greiner
  • 29,049
  • 9
  • 65
  • 85
  • Thanks.. I used "LinkedBlockingQueue" – Chathuranga Chandrasekara May 21 '09 at 13:59
  • awesome, is that everything you needed? I'm working on an example right now if you still want me to post it – Robert Greiner May 21 '09 at 14:01
  • Better you post it. Just a short example :) – Chathuranga Chandrasekara May 21 '09 at 14:02
  • alright, that is a very simple syntax example. Let me know if you need any other help. Good luck! – Robert Greiner May 21 '09 at 14:07
  • 1
    This won't work. You need to use put if you want it to block, or offer if you want it to return if it can't add the element. – Adam Jaskiewicz May 21 '09 at 14:09
  • you're right about add() i'm fixing it now, sorry about that I think take() should work however take() Retrieves and removes the head of this queue, waiting if no elements are present on this queue. http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/LinkedBlockingQueue.html – Robert Greiner May 21 '09 at 14:12
  • fixed, +1 for you Adam :P thanks for catching my careless mistake – Robert Greiner May 21 '09 at 14:13
  • Also, don't just catch the InterruptedException and print a stack trace. – Adam Jaskiewicz May 21 '09 at 14:15
  • Thanks a lot. But My target is bit different. I updated the question with my code. As an example I am asking about a scenario with list size limitation. As an example lets say we have a limitation of 1 in your lbq. – Chathuranga Chandrasekara May 21 '09 at 14:19
  • right, i'm assuming proper exception handling will be added later, I just wanted to show that you must catch (or throw) the Interrupted Exception. – Robert Greiner May 21 '09 at 14:22
  • @robbotic Logic like that is how that idiom gets into articles that pop up on DevZone. From there, it ends up in production code, and I have to fix it three years later when people decide they actually care that the application doesn't shut down cleanly (or they'll just sleep three seconds and do a System.exit(0)). – Adam Jaskiewicz May 21 '09 at 16:15
1

To specifically answer your question: Offer is a nonblocking offer call, so in a single threaded method like the one you posted, the call to offer('E') simply returns false without modifying the full queue. If you used the blocking put('E') call, it would sleep until space became available. Forever in your simple example. You would need to have a separate thread reading off of the queue to create space for the put to complete.

lostlogic
  • 1,514
  • 12
  • 10
0

Hi more info this class

 /**
 * Inserts the specified element into this queue if it is possible to do
 * so immediately without violating capacity restrictions, returning
 * {@code true} upon success and throwing an
 * {@code IllegalStateException} if no space is currently available.
 * When using a capacity-restricted queue, it is generally preferable to
 * use {@link #offer(Object) offer}.
 *
 * @param e the element to add
 * @return {@code true} (as specified by {@link Collection#add})
 * @throws IllegalStateException if the element cannot be added at this
 *         time due to capacity restrictions
 * @throws ClassCastException if the class of the specified element
 *         prevents it from being added to this queue
 * @throws NullPointerException if the specified element is null
 * @throws IllegalArgumentException if some property of the specified
 *         element prevents it from being added to this queue
 */
boolean add(E e);

/**
 * Inserts the specified element into this queue if it is possible to do
 * so immediately without violating capacity restrictions, returning
 * {@code true} upon success and {@code false} if no space is currently
 * available.  When using a capacity-restricted queue, this method is
 * generally preferable to {@link #add}, which can fail to insert an
 * element only by throwing an exception.
 *
 * @param e the element to add
 * @return {@code true} if the element was added to this queue, else
 *         {@code false}
 * @throws ClassCastException if the class of the specified element
 *         prevents it from being added to this queue
 * @throws NullPointerException if the specified element is null
 * @throws IllegalArgumentException if some property of the specified
 *         element prevents it from being added to this queue
 */
boolean offer(E e);

/**
 * Inserts the specified element into this queue, waiting if necessary
 * for space to become available.
 *
 * @param e the element to add
 * @throws InterruptedException if interrupted while waiting
 * @throws ClassCastException if the class of the specified element
 *         prevents it from being added to this queue
 * @throws NullPointerException if the specified element is null
 * @throws IllegalArgumentException if some property of the specified
 *         element prevents it from being added to this queue
 */
void put(E e) throws InterruptedException;

/**
 * Inserts the specified element into this queue, waiting up to the
 * specified wait time if necessary for space to become available.
 *
 * @param e the element to add
 * @param timeout how long to wait before giving up, in units of
 *        {@code unit}
 * @param unit a {@code TimeUnit} determining how to interpret the
 *        {@code timeout} parameter
 * @return {@code true} if successful, or {@code false} if
 *         the specified waiting time elapses before space is available
 * @throws InterruptedException if interrupted while waiting
 * @throws ClassCastException if the class of the specified element
 *         prevents it from being added to this queue
 * @throws NullPointerException if the specified element is null
 * @throws IllegalArgumentException if some property of the specified
 *         element prevents it from being added to this queue
 */
boolean offer(E e, long timeout, TimeUnit unit)
    throws InterruptedException;

/**
 * Retrieves and removes the head of this queue, waiting if necessary
 * until an element becomes available.
 *
 * @return the head of this queue
 * @throws InterruptedException if interrupted while waiting
 */
E take() throws InterruptedException;

/**
 * Retrieves and removes the head of this queue, waiting up to the
 * specified wait time if necessary for an element to become available.
 *
 * @param timeout how long to wait before giving up, in units of
 *        {@code unit}
 * @param unit a {@code TimeUnit} determining how to interpret the
 *        {@code timeout} parameter
 * @return the head of this queue, or {@code null} if the
 *         specified waiting time elapses before an element is available
 * @throws InterruptedException if interrupted while waiting
 */
E poll(long timeout, TimeUnit unit)
    throws InterruptedException;
Ahmad Aghazadeh
  • 16,571
  • 12
  • 101
  • 98