Почему ArrayBlockingQueue не блокируется, когда очередь заполнена

У меня есть простой тест для ArrayBlockingQueue, как показано ниже:

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

Результат:

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

моя проблема в том, что я определил размер ArrayBlockingQueue как 3, в то время как производитель поместил 2, 0 и 1, всего 3 элемента в очередь, и очередь теперь заполнена, тогда потребитель потреблял 0, размер сейчас очередь должна быть 2, а потом, производитель поставил 4 в очередь, сейчас очередь должна быть заполнена, почему производитель все еще может поставить 6 в очередь, она должна быть заблокирована


person gesanri    schedule 12.08.2018    source источник
comment
Проблема заключается в печати, System.out.println не является потокобезопасным, поэтому это может выглядеть как значение было вставлено в полную очередь.   -  person Guy    schedule 12.08.2018
comment
@Guy Почему следует винить System.out.println? Это потокобезопасно.   -  person xingbin    schedule 12.08.2018


Ответы (2)


Действие «взять/положить» и печать не являются атомарными.

producer: 6 печатается перед consumer: 2, это не означает, что производитель помещает 6 до того, как потребитель потребляет 2.

Например:

  1. потребитель выполнить queue.take() и взять 2
  2. производитель выполнить queue.put(6)
  3. производитель печати производитель: 6
  4. потребительская пинта потребитель: 2
person xingbin    schedule 12.08.2018

Тот факт, что producer: 6 выводится на вашу консоль перед consumer: 2, не означает, что 6 добавляется до того, как 2 удаляется.

Если вы напечатаете размер очереди до и после добавления и удаления элементов, вы увидите, что он никогда не превышает 3.

person Eran    schedule 12.08.2018