views:

574

answers:

3

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?

+2  A: 
Robert Greiner
Thanks.. I used "LinkedBlockingQueue"
Chathuranga Chandrasekara
awesome, is that everything you needed? I'm working on an example right now if you still want me to post it
Robert Greiner
Better you post it. Just a short example :)
Chathuranga Chandrasekara
alright, that is a very simple syntax example.Let me know if you need any other help.Good luck!
Robert Greiner
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
you're right about add() i'm fixing it now, sorry about thatI think take() should work howevertake() 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
fixed, +1 for you Adam :P thanks for catching my careless mistake
Robert Greiner
Also, don't just catch the InterruptedException and print a stack trace.
Adam Jaskiewicz
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
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
@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
+5  A: 

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
Previously I used Add + Poll. But at the moment I am trying out put + Take
Chathuranga Chandrasekara
Hmm.... Got the point.. Experimenting now :)
Chathuranga Chandrasekara
How should I specify the timeout for the PUT()?
Chathuranga Chandrasekara
Put doesn't have a timeout; if you need a timeout, use offer.
Adam Jaskiewicz
+1  A: 

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
replaces offer with put but failed. Do i need to use a seperate thread for PUT() the items?
Chathuranga Chandrasekara
In my answer, I said: You would need to have a separate thread reading off of the queue to create space for the put to complete.
lostlogic
Yes. Got the point :)
Chathuranga Chandrasekara