Ali Dehkhodaei
Ali Dehkhodaei

Reputation: 444

ArrayBlockingQueue+synchronized in java

I use ArrayBlockingQueue in my code and it has any element. But threads calls to take method. why? I think put method before take method should called. sorry for the bad writing.

Upvotes: 1

Views: 213

Answers (2)

James
James

Reputation: 1115

How do you know it isn't blocking until an item is available?

You should log the item that is removed from the queue as well. And ideally include some Id that helps identify unique values such as the thread name when you put.

Remember the methods on the queue are atomic, your logging is not, so it might happen out of order in comparison to the events you are trying to debug.

To make this more obvious, I would adding logging before the blocking methods that show which threads are waiting.

I also save something so it is easy to see where the message taken has come from. This way you can see that the methods are blocking and working as expected.

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class ArrayBlockingQueueExample {
    public static void main(String[] args) {
        ArrayBlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
        Thread[] threads = {
            new Producer(blockingQueue),
            new Producer(blockingQueue),
            new Producer(blockingQueue),
            new Producer(blockingQueue),
            new Producer(blockingQueue),
            new Consumer(blockingQueue),
            new Consumer(blockingQueue),
            new Consumer(blockingQueue),
            new Consumer(blockingQueue),
            new Consumer(blockingQueue),
        };

        for(Thread t: threads) {
            t.start();
        }
    }

    static class Consumer extends Thread {
        private final BlockingQueue<String> queue;

        Consumer(BlockingQueue<String> queue) {
            this.queue = queue;
        }

        @Override
        public void run() {
            try {
                System.out.println("Consumer:" + this.getName() + " waiting... ");
                String takenValue = queue.take();
                // Logging here may occur out of order in comparison with the producer thread logging.
                System.out.println("Consumer:" + this.getName() + " received: " + takenValue);
            } catch (InterruptedException e) {
                // Reset the interrupted flag on the thread.
                Thread.currentThread().interrupt();
                e.printStackTrace();
            }
        }
    }

    static class Producer extends Thread {
        private final BlockingQueue<String> queue;

        Producer(BlockingQueue<String> queue) {
            this.queue = queue;
        }

        @Override
        public void run() {
            try {
                String putValue = "Producer:" + this.getName() + " says hello!";
                System.out.println("Producer:" + this.getName() + " waiting... ");
                queue.put(putValue);
                // Logging here may occur out of order in comparison with the consumer thread logging.
                System.out.println("Producer:" + this.getName() + " sent: " + putValue);
            } catch (InterruptedException e) {
                // Reset the interrupted flag on the thread.
                Thread.currentThread().interrupt();
                e.printStackTrace();
            }
        }
    }
}

With this code you will see something like the following output:

Consumer:Thread-5 waiting... 
Consumer:Thread-7 waiting... 
Producer:Thread-1 waiting... 
Producer:Thread-0 waiting... 
Producer:Thread-4 waiting... 
Consumer:Thread-9 waiting... 
Consumer:Thread-8 waiting... 
Consumer:Thread-6 waiting... 
Producer:Thread-2 waiting... 
Producer:Thread-3 waiting... 
Consumer:Thread-6 received: Producer:Thread-0 says hello!
Producer:Thread-2 sent: Producer:Thread-2 says hello!
Consumer:Thread-5 received: Producer:Thread-3 says hello!
Producer:Thread-1 sent: Producer:Thread-1 says hello!
Consumer:Thread-7 received: Producer:Thread-4 says hello!
Consumer:Thread-8 received: Producer:Thread-1 says hello!
Producer:Thread-3 sent: Producer:Thread-3 says hello!
Producer:Thread-4 sent: Producer:Thread-4 says hello!
Consumer:Thread-9 received: Producer:Thread-2 says hello!
Producer:Thread-0 sent: Producer:Thread-0 says hello!

Notice that the consumer (Thread-6) received hello from the Thread-0 producer in the first line of logging, but the sent logging from Thread-0 is the last line logged? This order has nothing to do with the sequence of put events on the blocking queue.

Upvotes: 1

Bohemian
Bohemian

Reputation: 425033

It doesn’t matter what order put() and take() are executed - the effect is the same, because they are blocking calls.

take() takes and returns the next item, waiting for one if none are available.

put() adds an item, waiting for one to be taken if no space is available.

Upvotes: 1

Related Questions