views:

297

answers:

3

I would like to have a SynchronousQueue where I insert elements from one thread with put(), so the input is blocked until the element is taken in another thread.

In the other thread I perform lots of calculations and from time to time want to check if an element is already available, and consume it. But it seems that isEmpty() always returns true, even if another thread is waiting at the put() call.

How on earth is this possible? Here is the sample code:

@Test
public void testQueue() throws InterruptedException {
    final BlockingQueue<Integer> queue = new SynchronousQueue<Integer>();

    Thread t = new Thread(new Runnable() {
        @Override
        public void run() {
            while (true) {
                if (!queue.isEmpty()) {
                    try {
                        queue.take();
                        System.out.println("taken!");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // do useful computations here (busy wait)
            }
        }
    });
    t.start();

    queue.put(1234);
    // this point is never reached!
    System.out.println("hello");
}

EDIT: Neither isEmpty() nor peek() work, one has to use poll(). Thanks!

+4  A: 

From http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/SynchronousQueue.html#put(E) :

isEmpty
public boolean isEmpty()
Always returns true. A SynchronousQueue has no internal capacity.

(haven't looked into this in great detail, but you might want to take a look at either poll or take instead)

Tim
oh my, I should have read the javadoc... I have tried both peek() and isEmpty(), and both always return null or true.
martinus
+1  A: 

In addition to Tim's answer - you are doing nothing in the consumer thread but continuously calling isEmpty() in a tight loop. Rather than asking the OS to not run it until there is something useful for it to do, the consumer thread is continuously busy. Even if isEmpty worked correctly, the producer thread would rarely get a chance to run.

You could (if isEmpty() did work, or you switched to using poll()) make the consumer sleep for a bit between tests when the queue is empty to give the producer a chance to run, or (preferably) just take out the isEmpty() test and let the thread block on the mutex inside the take() in a sensible manner instead of polling.

moonshadow
+1  A: 

your code looks like you are trying to do a poll. why not just call the poll() method?

james