BlockingQueue и Capacity

Вопрос такой: Почему, если capacity = 5, то при запуске программы, в консоли иногда проскакивают Producer и Consumer чаще, чем по 5 раз подряд?
Пример:

Producer 50
Producer 43
Producer 30
Producer 43
Producer 41
Producer 88
Producer 36
Consumer 50
Consumer 43
Consumer 30
Consumer 43

Почему продюсера 7 шт?

public class ProducerConsumerProblemWIthQueue {
    public static final BlockingQueue<Integer> buffer = new ArrayBlockingQueue<>(5);

    public static void problemWIthQueue() {
        Thread producer = new Thread(() -> {
            while (true) {
                produce();
            }
        });

        Thread consumer = new Thread(() -> {
            while (true) {
                consumer();
            }
        });

        producer.start();
        consumer.start();
    }

    private static void produce() {
        int randomInt = ThreadLocalRandom.current().nextInt(100);
        System.out.println("Producer " + randomInt);
        try {
            buffer.put(randomInt);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    private static void consumer() {
        Integer take;
        try {
            take = buffer.take();
            System.out.println("Consumer " + take);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

Ответы (1 шт):

Автор решения: Nowhere Man

Основная проблема представленного кода в том, что метод produce печатает значения до вызова блокирующего метода put.

Если организовать вывод после вызова блокирующего метода и показывать содержимое очереди:

private static void produce() {
    int randomInt = ThreadLocalRandom.current().nextInt(100);
    try {
        buffer.put(randomInt);
        System.out.println("Producer: " + randomInt + " -> " + buffer);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
}

можно увидеть следующую картину:

Consumer: 9 -> []
Producer: 9 -> [9]
Producer: 5 -> [5]
Consumer: 5 -> []
Producer: 83 -> [83]
Consumer: 83 -> []
Producer: 56 -> [56]
Consumer: 56 -> []
Producer: 44 -> [44]
Consumer: 44 -> []
Producer: 72 -> [72]
Consumer: 72 -> []
Producer: 27 -> [27]
Consumer: 27 -> []
Consumer: 21 -> []
Producer: 21 -> [21]
Consumer: 5 -> []
Producer: 5 -> [5]
Producer: 3 -> [3]
Consumer: 3 -> []

то есть, вывод будет несинхронизирован относительно изменений в самой очереди: сообщение из потока consumer попадает в поток вывода раньше, чем из потока producer, и аналогично в выводе может появиться 6 и более сообщений из потока producer, но при этом в самой очереди не будет более 5 элементов:

Producer: 73 -> [73]
Producer: 13 -> [13]
Producer: 32 -> [13, 32]
Producer: 77 -> [13, 32, 77]
Producer: 56 -> [13, 32, 77, 56]
Producer: 77 -> [13, 32, 77, 56, 77]
Consumer: 73 -> []
Consumer: 13 -> [32, 77, 56, 77]
Producer: 82 -> [32, 77, 56, 77, 82]
Consumer: 32 -> [77, 56, 77, 82]
Producer: 30 -> [77, 56, 77, 82, 30]
Consumer: 77 -> [56, 77, 82, 30]
Producer: 86 -> [56, 77, 82, 30, 86]
Consumer: 56 -> [77, 82, 30, 86]
→ Ссылка