davidchoo12
davidchoo12

Reputation: 1331

Java BlockingQueue take() in a while loop

I have a BlockingQueue which is being populated by a thread with put(). But I am confused on how to do take() for the BlockingQueue. Currently I implemented it this way:

String link;
try {
    while(!(link = links.take()).isEmpty()) {
        System.out.println(link);
    }
} catch(InterruptedException ex) {
    ex.printStackTrace();
}

Is that right? How is it possible to loop the queue and assign the string variable if not within the conditional statement?

Upvotes: 4

Views: 4711

Answers (2)

beatngu13
beatngu13

Reputation: 9443

If I have understood correctly, you have asked for a way to take outside of the condition? Well, it's not that hard:

while (!links.isEmpty()) {
    try {
        String link = links.take();
        // Do stuff.
    } catch (InterruptedException e) {
        // Exception handling.
    }
}

Your current condition !(link = links.take()).isEmpty() checks if the return value—a string—is empty (length equals 0), not the queue.

Anyhow, please bear in mind that the code above is not atomic, so there's no guarantee that nothing else happens between links.isEmpty() and links.take().

EDIT: You can handle race conditions during the startup with a flag:

BlockingQueue<Integer> numbers = new ArrayBlockingQueue<>(10);
AtomicBoolean flag = new AtomicBoolean(true);

// Producer.
new Thread(() -> {
    for (int i = 0; i < 10; i++) {
        try {
            numbers.put(i);
        } catch (InterruptedException e) { /* NOP */ }
    }
    flag.set(false);
}).start();

// Consumer.
while (flag.get() || !numbers.isEmpty()) {
    try {
        System.out.println(numbers.take());
    } catch (InterruptedException e) { /* NOP */ }
}

The AtomicBoolean is not necessary here, but it might become handy if you have multiple producers and/or consumers. It's also part of java.util.concurrent which you definitely should checkout.

Upvotes: 2

Alexander Petrov
Alexander Petrov

Reputation: 9492

My understanding is that you are asking on how to terminate a BlockingQueue in a good way. There are two scenarios I can think of. In any case you have a Message producer A and message consumer B.

  1. Message producer sends some form of a terminal value like "Stop". You check against it and the while cycle terminates.
  2. You can interrupt the message producer which will throw InterruptedException on the consumer side. This is the way to avoid the terminal input case. The problem here is that you dont't have control if the consumer has actually consumed everything that is on the queue. So interruption is usually used if there is a condition that requires the consuming to terminate imediately.

Upvotes: 0

Related Questions