2

I have a simple test for ArrayBlockingQueue as below:

public class TestQueue {

    static class Producer implements Runnable {
        private ArrayBlockingQueue<Integer> queue;
        private int index;

        public Producer(ArrayBlockingQueue<Integer> queue, int index) {
            this.queue = queue;
            this.index = index;
        }

        @Override
        public void run() {
            try {
                queue.put(index);

                System.out.println("producer: " + index);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static class Consumer implements Runnable {
        private ArrayBlockingQueue<Integer> queue;

        public Consumer(ArrayBlockingQueue<Integer> queue) {
            this.queue = queue;
        }

        @Override
        public void run() {
            try {
                while(true) {
                    System.out.println("consumer: " + queue.take());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(3);

        for (int i = 0; i < 10; i++) {
            Producer producer = new Producer(queue, i);

            new Thread(producer).start();
        }

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Consumer consumer = new Consumer(queue);

        new Thread(consumer).start();
    }
}

The result is:

producer: 2
producer: 0
producer: 1
consumer: 0
producer: 4
producer: 6
consumer: 2
etc...

my problem is, I have defined the size of ArrayBlockingQueue as 3, while the producer has put 2, 0 and 1, totally 3 items into the queue, and the queue is full now, then the consumer has consumed 0, the size of the queue should be 2 now, and then, the producer put 4 into the queue, the queue should be full now, why the producer can still put 6 into the queue, it's supposed to be blocked

xingbin
  • 27,410
  • 9
  • 53
  • 103
gesanri
  • 237
  • 1
  • 3
  • 10
  • 1
    The problem is in the printing, `System.out.println` [is not thread safe](https://stackoverflow.com/questions/9459657/synchronization-and-system-out-println) so it might look like the value was inserted to a full queue. – Guy Aug 12 '18 at 09:58
  • @Guy Why should `System.out.println` be blamed? It's thread safe. – xingbin Aug 12 '18 at 10:44

2 Answers2

1

The take/put action and the print are not atomic.

producer: 6 is printed before consumer: 2, does not mean the producer put 6 before the consumer consume 2.

For example:

  1. consumer execute queue.take(), and take 2
  2. producer execute queue.put(6)
  3. producer print producer: 6
  4. consumer pint consumer: 2
xingbin
  • 27,410
  • 9
  • 53
  • 103
0

The fact that producer: 6 is printed to your console before consumer: 2, doesn't mean that 6 is added before 2 is removed.

If you printed the size of the queue before and after adding and removing items, you would see that it never exceeds 3.

Eran
  • 387,369
  • 54
  • 702
  • 768