Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Blocking Queue - Need more information

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?

like image 948
Chathuranga Chandrasekara Avatar asked May 21 '09 13:05

Chathuranga Chandrasekara


2 Answers

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.

like image 135
Michael Myers Avatar answered Sep 29 '22 23:09

Michael Myers


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();
}

like image 21
Robert Greiner Avatar answered Sep 30 '22 00:09

Robert Greiner